Mysql事务和锁

脏读:在A事务中读到B事务中修改而未提交的数据
不可重复读:在A事务中读到B事务中修改或删除并提交的数据
幻读:A事务中读到B事务插入数据并提交的数据

  • 解决方案:
    Mysql事务和锁_第1张图片
    要保证在一个事务中前后两次读取的数据结果一致,实现事务隔离需
    Mysql事务和锁_第2张图片
    第一种加锁,效率不高,关键位置需使用
    第二种在事务中不会受到其他事务的影响,像镜像一样

  • mysql的锁
    Mysql事务和锁_第3张图片
    图中问题 MylSAM只支持表锁,InnoDB支持表锁和行锁

InnoDB默认支持的是行锁,但这并不代表InnoDB不支持表锁。必须明白这一点在InnoDB中并不是在数据行上加锁,而是在对应的索引上加锁。这种实现的特点是:只有通过索引条件检索数据的时候加的是行锁,否则加表锁!

1.行锁

行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。
行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。有可能会出现死锁的情况
行级锁按照使用方式分为共享锁和排他锁。

共享锁用法(S锁 读锁):

​ 若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

排它锁用法(X 锁 写锁):

​ 若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。
排它锁,也称作独占锁,一个锁在某一时刻只能被一个线程占有,其它线程必须等待锁被释放之后才可能获取到锁。

2.表锁

​ 表级锁是mysql锁中粒度最大的一种锁,表示当前的操作对整张表加锁,**资源开销比行锁少,不会出现死锁的情况,但是发生锁冲突的概率很大。**被大部分的mysql引擎支持,MyISAM和InnoDB都支持表级锁,但是InnoDB默认的是行级锁。

InnoDB锁的特性

  1. 在不通过索引条件查询的时候,InnoDB使用的确实是表锁!
  2. 由于 MySQL 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行 的记录,但是如果是使用相同的索引键,是会出现锁冲突的。这里就要知道B+树的原理了,如下图
    Mysql事务和锁_第4张图片
    b+树中的非叶子节点存的是聚集索引(主键索引),叶子节点才是存放数据的地方,右边是非聚集索引(普通索引),这种索引为了节省空间,索引值和主键绑定在一起,然后再去左边找,就会发现这个主键已经被锁住了,所以虽然是访问不同行的记录,但是依旧不行。
    另外就可以解释为什么没有使用索引搜索则是表锁,是因为表中数据都有一个隐藏的rowId,所以说还是用的索引(rowId),表中所有行就都被锁住了。
  3. 当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论 是使用主键索引、唯一索引或普通索引,InnoDB 都会使用行锁来对数据加锁。
  4. 即便在条件中使用了索引字段,但是否使用索引来检索数据是由 MySQL 通过判断不同 执行计划的代价来决定的,如果 MySQL 认为全表扫 效率更高,比如对一些很小的表,它 就不会使用索引,这种情况下 InnoDB 将使用表锁,而不是行锁。因此,在分析锁冲突时, 别忘了检查 SQL 的执行计划,以确认是否真正使用了索引。

3.Record Lock、Gap Lock、Next-key Lock锁

1.Record Lock

​ 单条索引上加锁,record lock 永远锁的是索引,而非数据本身,如果innodb表中没有索引,那么会自动创建一个隐藏的聚集索引,锁住的就是这个聚集索引。所以说当一条sql没有走任何索引时,那么将会在每一条聚集索引后面加X锁,这个类似于表锁,但原理上和表锁应该是完全不同的。
这种是最常规的
Mysql事务和锁_第5张图片

2.Gap Lock

间隙锁,是在索引的间隙之间加上锁,这是为什么Repeatable Read隔离级别下能防止幻读的主要原因。
Mysql事务和锁_第6张图片
假设id为1,4,7,10是有数据的
如果 where id=5 for update ,锁住的区间就是 5的左右有记录区间也就是(4,7),如图
为什么说gap锁是RR隔离级别下防止幻读的主要原因。
快照读:简单的select操作,没有lock in share mode或for update

当前读:官方文档的术语叫locking read,也就是insert,update,delete,select…in share mode和select…for update,当前读会在所有扫描到的索引记录上加锁,不管它后面的where条件到底有没有命中对应的行记录。

​ 首先了解到InnoDB索引的数据结构是B+树,其索引是有序性的,如何保证两次当前读返回一致的记录,那就需要在第一次当前读与第二次当前读之间,其他的事务不会插入新的满足条件的记录并提交。注意是当前读。

3.Next-Key Lock

这个锁机制其实就是前面两个锁相结合的机制,行锁就是采用这个锁的机制用来防止幻读!
Mysql事务和锁_第7张图片

你可能感兴趣的:(Mysql事务和锁)