MyISAM与InnoDB 的区别(9个不同点)

参考链接 https://blog.csdn.net/qq_35642036/article/details/82820178

1. InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务;

2. InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败;

3.InnoDB是聚集索引,使用B+Tree作为索引结构,数据文件是和(主键)索引绑在一起的(表数据文件本身就是按B+Tree组织的一个索引结构),必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。
MyISAM是非聚集索引,也是使用B+Tree作为索引结构,索引和数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。
也就是说:InnoDB的B+树主键索引的叶子节点就是数据文件,辅助索引的叶子节点是主键的值;而MyISAM的B+树主键索引和辅助索引的叶子节点都是数据文件的地址指针。
4. InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。而MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快(注意不能加有任何WHERE条件);
5. Innodb不支持全文索引,而MyISAM支持全文索引,在涉及全文索引领域的查询效率上MyISAM速度更快高;PS:5.7以后的InnoDB支持全文索引了

6. MyISAM表格可以被压缩后进行查询操作

7. InnoDB支持表、行(默认)级锁,而MyISAM支持表级锁

8. InnoDB表必须有主键(用户没有指定的话会自己找或生产一个主键),而Myisam可以没有

9. Innodb存储文件有frm、ibd,而Myisam是frm、MYD、MYI

  1. Innodbfrm是表定义文件,ibd是数据文件
  2. Myisamfrm是表定义文件,myd是数据文件,myi是索引文件

如何选择:

  1. 是否要支持事务,如果要请选择innodb,如果不需要可以考虑MyISAM;
  2. 如果表中绝大多数都只是读查询,可以考虑MyISAM,如果既有读也有写,请使用InnoDB。
  3. 系统奔溃后,MyISAM恢复起来更困难,能否接受;
  4. MySQL5.5版本开始InnoDB已经成为Mysql的默认引擎(之前是MyISAM),说明其优势是有目共睹的,如果你不知道用什么,那就用InnoDB,至少不会差。

InnoDB为什么推荐使用自增ID作为主键?

答:自增ID可以保证每次插入时B+索引是从右边扩展的,可以避免B+树和频繁合并和分裂(对比使用UUID)。如果使用字符串主键和随机主键,会使得数据随机插入,效率比较差。

innoDB引擎的4大特性

插入缓冲(insert buffer)
二次写(double write)
自适应哈希索引(ahi)
预读(read ahead)

事务

参考链接 https://blog.csdn.net/dengjili/article/details/82468576

ACID原则

  • 原子性(Atomicity)
    要么都成功,要么都失败。
  • 一致性(Consistency)
    事务前后数据的完整性必须保持一致。
  • 隔离性(Isolation)
    事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
  • 持久性(Durability)
    持久性是指一个事务一旦被提交,则不可逆转

JDBC操作事务的api方法使用思路

    Class.forName("com.mysql.jdbc.Driver");
    String user = "root";
    String password = "123456";
    Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx", user, password);
  1. 开启事务,关闭自动提交,然后执行插入或更新语句——执行connection.setAutoCommit(false)
  2. 执行完毕无出错,提交——connection.commit()
  3. catch捕获到异常,回滚——connection.rollback()

事务隔离

事务隔离可能导致的问题

更新丢失

最后更新的事务覆盖其他事务的更新, 例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。

脏读

当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。

不可重复读

指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。

虚读(幻读)

幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

事务隔离级别

image.png

查看当前数据库隔离级别,mysql默认级别是可重复读

show variables like 'tx_isolation';

事务的SQL写法

MySQL默认开启事务自动提交,可以设置关闭

手动操作事务提交

-- 1为开启自动提交(默认) 0为关闭
set autocommit=0
-- 事务开启
start transaction
-- 插入操作更新操作等...此处省略

-- 执行成功就可以提交 事务一旦提交就持久化
commit
-- 回滚 提交后再回滚就没有用了
rollback
-- 事务结束 开启自动提交
set autocommit=1

-- 其他操作
-- 设置一个事务的保存点
savepoint [保存点名] 
-- 回滚到保存点
rollback to savepoint [保存点名]
-- 移除保存点
release savepoint [保存点名]

索引

MySQL官方对索引的定义为:索引(index)是帮助MySQL高效获取数据的数据结构(有序)。 索引主要用途:排序+查找

索引数据结构详解链接 http://blog.codinglabs.org/articles/theory-of-mysql-index.html

索引分类

单值索引,唯一索引,复合索引

  • 主键索引(PRIMARY KEY)
    • 设置主键自动创建
  • 唯一索引(UNIQUE KEY)
    • 避免重复的字段的值
  • 常规索引(INDEX)
    • 默认的,index,key关键字来设置
    • 这是最基本的索引类型,而且它没有唯一性之类的限制
  • 全文索引(FULLTEXT)
    • 在特定的数据库引擎下才有,比如MyISAM,5.7版本以后的InnoDB
    • 适合在进行模糊查询的时候使用,可以在CHAR、VARCHAR或者TEXT类型的列上创建,FULLTEXT用于搜索很长一篇文章的时候,效果最好

索引的结构和原理:

  • BTree:一般指的都是B+Tree
  • Hash:只有Memory引擎支持,使用简单
  • Full-text:原本是MyISAM引擎的一个特殊索引,InnoDB从5.6开始支持
  • R-Tree:只有MyISAM引擎支持,使用较少

平常所说的索引,如果没有特别指明,都是指B+Tree结构的索引,其中聚集索引,复合索引,前缀索引,唯一索引默认都是使用B+Tree索引,统称为索引

BTree

多路平衡搜索树,m叉树

  • 每个节点最多包含m个孩子
  • 除根节点和叶子节点外,每个节点至少有[ceil(m/2)](向上取整)个孩子
  • 如果根节点不是叶子节点,则至少有两个孩子
  • 所有叶子节点都在同一层
  • 每个非叶子节点由n个key和n+1个指针组成,其中[ceil(m/2)] <= n <= m-1,当n>m-1时中间节点分裂到父节点,两边节点分裂

以3叉B树为例,查找时假设17和35为关键字,通过范围选择指针,小于17的用p1,17到35之间的用p2,大于35的用p3,据根结点指针找到文件目录的根磁盘块1,将其中的信息导入内存
image.png

B+Tree

B+Tree才是mysql索引使用的数据结构,B+Tree为BTree的变种,区别为:

  1. n叉B+Tree最多含有n个key,而BTree最多含有n-1个key
  2. B+Tree的叶子节点保存所有的key信息,依key大小顺序排列,这样做可以增大度
  3. 所有的非叶子节点都可以看作是key的索引部分,不存储数据
  4. 由于只有叶子节点保存key信息,查询任何key都要从root走到叶子,所以B+Tree查询效率更稳定

image.png

MySQL中的B+Tree

mysql索引对经典B+Tree进行了优化,在原+Tree的基础上,增加一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+Tree,提高区间访问的性能,范围查找更方便了

image.png

Hash索引

hash算法+数组

优缺点:

  • 键值唯一,hash索引明显有绝对优势
  • 无法完成范围查询检索
  • 无法利用索引完成排序,以及like ‘xxx%’ 这样的部分模糊查询
  • 不支持多列联合索引
  • 因为hash碰撞问题,检索效率低

索引的创建

-- 显示所有的student表的索引
show index from student

-- 增加一个全文索引
alter table student add FULLTEXT INDEX studentName (studentName);

-- EXPLAIN 分析sql执行的状况,例:
explain select * from student;

-- 使用create index创建索引
-- create index 索引名 on 表(字段)
create index idx_name on student(studentName)
-- 创建复合索引 where 后多个and的时候有效 on
-- create index 索引名 on 表(字段,字段...)
create index idx_name_class on student(studentName,age)

当表内数据非常多的时候,直接使用select语句查询效率就会非常低,创建索引之后查询的效率将大大提升

  • 没加索引——遍历
  • 加了索引——定位

索引原则

  • 索引不是越多越好
  • 不要对经常变动的数据字段加索引
  • 查询中与其他表管理的字段,外键关系建立索引
  • 小数据量的表不需要加索引
  • where条件用不到的字段不创建索引
  • 索引一般加载经常用来查询的字段上
  • 排序字段,排序字段若通过索引去访问将大大提高排序速度
  • 统计或分组的字段可以建索引 group by 操作

索引最佳左前缀原则:

带头大哥不能死,中间小弟不能断

用于在WHERE子句、join子句、ORDER BY或GROUP BY子句中的列。

例如这里创建一个索引,复合索引

CREATE INDEX idx_nameAgePos ON staff(name, age, pos);

查询使用到where时为了让索引生效,每个比对的字段都用上索引

需要满足最佳左前缀原则,查询要么使用name,要么name和age,要么name和age和pos

where name = xxx 
where name = xxx and age = yyy
where name = xxx and age = yyy and pos = zzz
where age = yyy and pos = zzz and name = xxx

依次类推保证列的左边也是索引列,也就是

带头大哥不能死,中间小弟不能断

查询字段与索引字段顺序的不同会导致,索引无法充分使用,甚至索引失效!

不在索引列上做任何操作(计算、函数、(自动or 手动)类型转换),会导致索引失效而转向全表扫描。

聚集索引和非聚集索引

聚集索引

也叫聚簇索引,不是单独的索引类型,而是一种存储方式,指的是数据行和相邻的键值存储在一起

大家熟知的InnoDB就是聚簇,而MyISAM就是非聚簇,两者区别就在于InnoDB在同一结构中保存了BTREE的索引+数据row(存放于叶子页中)。
image.png

对于没有主键和唯一索引的表,InnoDB会隐式定义一个row_id来作为聚簇索引(你不给我我就自己造)
非聚集索引

非聚集(unclustered)索引。

该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同,一个表中可以拥有多个非聚集索引。

数据文件和索引文件分开存放

细分一下非聚集索引,分成普通索引,唯一索引,全文索引。

非聚集索引的二次查询问题

非聚集索引叶节点仍然是索引节点,只是有一个指针指向对应的数据块,此如果使用非聚集索引查询,而查询列中包含了其他该索引没有覆盖的列,那么他还要进行第二次的查询,查询节点上对应的数据行的数据。

覆盖索引

一个索引包含了所有我们要查的值,索引列包含查询列

如果查询条件使用的是普通索引(或是联合索引的最左原则字段),查询结果是联合索引的字段或是主键,不用回表操作,直接返回结果,减少IO磁盘读写读取整行数据

如果查询列超过了索引列,也会降低性能

索引生效条件

like 以%开头,索引无效;当like前缀没有%,后缀有%时,索引有效。但这种情况并不绝对

查询条件是一个不以通配符开头的常量例如:
select from user where name like ‘jack%’;
select
from user where name like ‘jac%k%’;

如果以通配符开头,或者没有使用常量,则不会使用索引,例如:
select from user where name like ‘%jack’;
select
from user where name like simply_name;

like 以%开头,如果查询的列在复合索引中时会使索引生效

以下用法可能会导致索引失效

计算,如:+ 、-、 *、 /、 != 、 <> 、is null、 is not null、 or

!=是永远不会用到索引,key<>0 优化为 key>0 or key<0

or语句前后没有同时使用索引。当or左右查询字段只有一个是索引,该索引失效,只有当or左右查询字段均为索引时,才会生效

函数,如:sum(),round()等会导致索引失效

手动类型转换,如id=”1”,本来是整型,转成字符串了,5.7版本之后类型转换索引有效

范围查找之后的索引都失效,比如 a>100 and b ='100' (和b+树数据结构有关)

IS NULL 或 IS NOT NULL操作时,当null值占多数时is not null 和!=走索引 ,is null不走索引

SQL性能下降的问题

  • 查询语句写的烂
  • 索引失效:创建了索引,但没用上
  • 关联查询用了太多join

SQL执行加载顺序

image.png
image.png

explain性能分析

能干嘛

  • 表的读取顺序
  • 数据读取操作的操作类型
  • 哪些索引可以使用
  • 哪些索引被实际使用
  • 表之间的引用
  • 每张表有多少行被优化器查询

注意:如果要使用覆盖索引,一定注意select列表中只取出需要的列,不要select *

如果一个索引包含了(或覆盖了)满足查询语句中字段与条件的数据就叫 做覆盖索引。

使用: explain + sql语句

  • id:select查询的序列号,表示查询中执行select子句或操作表的顺序
    • id相同,执行顺序由上至下
    • id不同,如果是子查询id的序列号会递增,id值越大优先级越高
    • id不同与相同同时存在,永远是id值更大的优先,平级的顺序执行
  • select_type:什么样的类型查询
    • SIMPLE:简单的select查询,不包含子查询或UNION
    • PRIMARY:最外层查询,通常id值最低
    • SUBQUERY:在select或where列表中包含的子查询
    • DERIVED:在from列表中包含的子查询被标记为DERIVED(衍生表),mysql会递归执行这些子查询,把结果放在临时表里
    • UNION:若第二个select出现在union之后,则被标记为union;若union包含在from子句的子查询中,外层的select将被标记为DERIVED
    • UNION RESULT:从union表获取结果的select
  • table:表示这一行的数据是哪张表的,也有DERIVED(衍生表),后面接的id表示根据哪个子查询衍生的
  • type:访问类型,从最好到最差依次是 system>const>eq_ref>range>index>ALL,当然不止这几个,这些是常见的
    • system:表只有一行记录(等于系统表),平时不会出现,可以忽略不计
    • const:表示通过索引一次就找到了,用于比较primary key或unique索引,因为只匹配一行数据,所以很快,如将主键置于where表中,mysql就能将该查询转换为一个常量
    • eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配,常见于主键或唯一索引扫描
    • ref:非唯一性索引扫描,返回匹配某个单独值的所有行,可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体
    • range:只检索给定范围的行,使用一个索引来选择行,一般就是在where语句中出现的between、<、>、in 等的查询
    • index:full index scan 全索引扫描,index与ALL区别为index只遍历索引树,比ALL快,因为索引文件通常比数据文件小,都是全读表但是index是从索引中读取,而all是从硬盘中读取。select id from t1; 设置id索引,type会为index
    • ALL:全表扫描,大数据量出现这个建议要优化了
  • possible_keys:显示可能这张表中的索引,一个或多个,查询涉及到的字段上若存在索引,则索引将被列出,但不一定被查询使用,一句话就是,可能会用到的索引
  • key:实际使用的索引,如果为NULL,则没有使用索引,查询中若使用了覆盖索引,则该索引仅出现在key列表中
  • key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度,在不损失精确性的情况下,长度越短越好,显示的值为索引字段的最大可能长度,并非实际使用长度,根据定义计算而得,不是表内检索出的
  • ref:显示索引的哪一列被使用了,哪些列或常量被用于查找索引列上的值
  • rows:根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数,越少越好
  • Extra
    • Using filesort:文件内排序,说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。无法利用索引完成的排序操作。出现这个,如果可以尽快优化
    • Using temporary:使用临时表保存中间结果,在对查询结果排序时使用临时表。常见于排序order by和分组查询group by。出现这个,尽快优化
    • Using index:表示相应的select操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错。如果同时出现using where,表明索引被用来执行索引键值的查找,如果没有同时出现using where,表明索引用来读取数据而非执行查找
    • Using index condition:确实命中了索引,但不是所有的列数据都在索引树上,还需要访问实际的行记录。这类SQL语句性能也较高,但不如Using index。
    • Using where:SQL使用了where条件过滤数据,不代表不需要优化,往往需要配合explain结果中的type(连接类型)来综合判断
    • Using join buffer (Block Nested Loop):使用了连接缓存,需要进行嵌套循环计算。画外音:内层和外层的type均为ALL,rows均为4,需要循环进行4*4次计算。这类SQL语句性能往往也较低,需要进行优化。
    • impossible where:where子句总是false

优化的一些方法

分析方法:

  1. 开启慢查询日志并捕获,设置阈值,比如超过5秒就是慢sql,
  2. explain+慢SQL分析
  3. show profile
  4. SQL数据库服务器的参数调优

索引优化

单表优化

range类型查询字段的索引无效

-- 查询语句是这样
select id,author_id from article where category_id=1 and comments>1 order by views desc limit 1;
-- 已有索引
create index idx_article_ccv on article(category_id,comments,views);

看似满足索引最佳左前缀原则,但是comments是条件范围range,索引会失效,

使用explain查看会出现Using filesort

这时删掉原索引,建立如下索引

create index idx_article_cv on article(category_id,views);

把用到了范围查询的字段移除出复合索引

优化成为Using where,检索+排序+用到索引

join语句多表优化

left join条件用于确定如何从右表搜索行,所以右边是关键点,一定要建立索引

多表查询使用多个join时,保证join语句中被驱动表上join条件字段已经被索引

尽可能减少join语句中出现的 Nested Loop(尽可能减少Using join buffer):永远让小结果集驱动大结果集

当无法保证被驱动表条件字段且内存资源充足的前提,不要太吝惜join buffer的设置

in和exists的优化原则:小表驱动大表

exists的使用

语法为select ... from table where exists (子查询)

将主查询的数据,放到子查询中做条件验证,将验证的结果(true或false)来决定主查询的数据结果是否得以保留

B表的数据集必须小于A表数据集的时候,in优于exists

select * from A where id in (select id from B)

A表的数据集小于B表数据集的时候,exists优于in

select * from A where exists (select 1 from B where A.id = B.id)

Order by 索引优化

SQL支持两种方式的排序,FileSort和Index,Index效率更高,FileSort低

mysql扫描索引本身完成排序

可用explain查看使用的是哪一种,如果order by后面有多个列,那么就会排多次,index和filesort可能同时使用

order by满足两种情况,会使用index方式排序

  • order by 语句使用索引最左前列
  • where 子句与order by 子句条件列组合满足索引最左前列

所以,尽可能在索引列上完成排序操作,遵照索引最佳左前缀

Group by 优化

优化方法与order by差不多

group by是先排序后分组,遵照索引最佳左前缀原则

where比having优先读取,所以能在where中写的就尽量不要在having 中

慢SQL日志

慢查询SQL日志若非调优需要,不建议开启,会影响性能

先查看慢SQL日志是否打开,一般默认是关闭的

show variables like 'slow_query_log%';

打开它 set global slow_query_log=1; mysql重启后会消失

mysql> show variables like 'slow_query_log%';
+---------------------+---------------------------------+
| Variable_name       | Value                           |
+---------------------+---------------------------------+
| slow_query_log      | OFF                             |
| slow_query_log_file | /var/lib/mysql/tencent-slow.log |
+---------------------+---------------------------------+
2 rows in set (0.00 sec)

mysql> set global slow_query_log=1;
Query OK, 0 rows affected (0.05 sec)

mysql> show variables like 'slow_query_log%';
+---------------------+---------------------------------+
| Variable_name       | Value                           |
+---------------------+---------------------------------+
| slow_query_log      | ON                              |
| slow_query_log_file | /var/lib/mysql/tencent-slow.log |
+---------------------+---------------------------------+
2 rows in set (0.00 sec)

查看当前多少秒算慢,默认是10秒,10秒有点太长了可以改一下

show variables like 'long_query_time%';

把他改一下,例如改成三秒

set global long_query_time=3;

改完之后,再立即查看会发现没有改,这时候需要关闭当前连接的客户端,重新连一次就好了

slow_query_log_file显示的日志文件中就会 捕获所有执行超过3秒的语句及其所在的数据库

函数和存储过程 大批量插入数据库

有一个test表,结构如下
image.png

往此表里大批量插入数据,用到函数和存储过程

定义两个函数,一个随机生成字符串作为name,一个随机生成数字作为num

定义一个存储过程,调用上面的两个函数

存储过程和函数最大的区别就是,函数有返回值,存储过程没返回值

-- 从哪里开始  以$$表示结束
delimiter $$
-- 创建随机生成字符串的函数
create function rand_string(n int) returns VARCHAR(255)
BEGIN
-- 定义变量 设置默认值
declare chars_str varchar(100) default 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
declare return_str varchar(255) default '';
declare i int default 0;
while i < n do
-- 随机生成字符串
set return_str=concat(return_str,SUBSTRING(chars_str,floor(1+RAND()*52),1));
set i = i+1;
end while;
RETURN  return_str;
-- 这个函数写完了
end $$

delimiter $$
-- 创建随机生成数字的函数
CREATE FUNCTION rand_num() RETURNS int(5)
begin
DECLARE i int DEFAULT 0;
set i = floor(100+rand()*10);
return i;
end $$


delimiter $$
create procedure insert_test(in start int(10),in max_num int(10))
begin 
 declare i int default 0;
 -- 设置自动提交为0 不关闭就是写一次就一个commit浪费性能
 set autocommit=0;
 repeat
 insert into test(id,name,num) values(start+i,rand_string(6),rand_num());
 set i = i+1;
 until i = max_num
 end repeat;
 commit;
end $$

-- 以 ; 表示结束
delimiter ;
-- 调用存储过程 插入一万条数据
call insert_test(1,10000);

show profile

先开启

show variables like 'profiling';
-- 如果显示的是off就要将它开启
set profiling=on;

然后运行 show profile 之后就可以看到近15条语句执行情况
image.png

如果要查看更具体的信息

-- 查看cpu执行信息 io信息 251是上面显示的id
show profile cpu,block io for query 251

全局日志(线上环境不推荐)

set global general_log=1;
set global log_output='table';

此后,所编写的sql语句将会记录到mysql的general_log表中

可以使用命令查看

select * from mysql.general_log;

锁机制

-- 查看哪些库的哪些表添加了锁
show open tables;
-- 查看读锁状态 看Table_locks_waited的数值
show status like 'table%';

表级锁(鸡肋)

添加表级锁

-- 给test表添加读锁
lock table test read;
-- 给test表添加写锁
lock table test write;
-- 解锁
unlock tables;

读锁

设置的test表读锁的当前会话可以查询该表记录,其他会话也可以查询该表记录

当前会话不能查询其他没有锁的表,其他会话可以查询或更新未锁定的表

当前会话更新锁定的表会报错,其他会话更新上锁的表会阻塞,直到当前会话释放锁
image.png
image.png

写锁

上锁的当前会话独占查询+更新+插入操作

其他会话会阻塞直到当前会话释放锁
image.png

简单的说:读锁阻塞写,写锁阻塞读和写

行锁

innoDB与MyISAM的最大不同点:一是支持事务,二是行锁

有索引的情况下自动就是行锁

当前使用事务的时候,提交前只能看到自己修改的

读己之所写

更新但不提交,其他会话在更新同一行时会阻塞,直到当前会话的事务提交
image.png

如果两个事务修改的不是同一行,那就不会阻塞

锁定某一行(手动上锁)

主要是关键字 for update
image.png

索引失效,行锁变表锁

varchar类型列名设置索引,where后没有接单引号,那么在更新操作时,会阻塞其他会话的更新操作

b列是varchar类型,但是写sql语句时没有加单引号

mysql可以将int类型转换成varchar类型,但是会让行锁变表锁,导致会话2阻塞
image.png

所以说这是个需要注意的细节问题

间隙锁的危害

当我们用范围条件而不是相等条件检索数据,并请求共享或排它锁时,InnoDB会给符合条件的已有数据记录的索引项加锁,对于键值在条件范围内但并不存在的记录,叫做”间隙(GAP)”

InnoDB会对“间隙”加锁,也就是间隙锁

锁定范围内的所有键值,即使这个键值并不存在

间隙锁只存在于可重复读(RR)的事务隔离级别及以上

因为会话1的事务还未提交,所以会话2处于阻塞状态,这就是间隙锁的危害
image.png