MySQL Transaction
MySQL 事务
事务原子性
事务隔离 Isolation
MySQL 中锁设计的一般思想
MySQL 中的锁 (InnoDB) 使用的是两阶段锁协议,也就是说锁是在需要的时候加上的,加锁后是在完成所有操作后一次性释放的
事务的一般问题和事务隔离级别
多个事务之间并发操作,存在几个一般问题:脏读、不可重复读、幻读以及丢失更新,不同的隔离级别可以不同程度的解决这些问题。
read committed 和 read uncommitted 隔离级别下或 RR 隔离级别下
innodb_locks_unsafe_for_binlog
设置为ON
时,禁止binlog_format=statement
,详细分析和案例参考这里:MySQL · 特性分析 · InnoDB对binlog_format的限制,or MySQL Bug 23051
主要原因是在主从复制时,会引起主从数据不一致,statement 记录的的是执行语句,不同事务执行语句的顺序会严重影响在备库数据还原的状态。本质的原因是RC级别并不满足事务串行化执行要求,没有解决不可重复读和幻读。
幻读与Next-Key Locking
产生幻读的原因是,行锁只能锁住行,但新插入记录这个动作,要更新的是记录之间的“间隙”。因此,为了解决幻读问题,InnoDB 引入了新的锁,也就是间隙锁 (Gap Lock);间隙锁,锁的就是两个值之间的空隙
数据行是可以加上锁的实体,数据行之间的间隙,也是可以加上锁的实体;
行锁分读锁和写锁,读锁之间可以兼容,读写锁和写写锁都是互斥的,也就是说行锁之间是相互影响的;但是间隙锁不一样,跟间隙锁存在冲突关系的,是“往这个间隙中插入一个记录”这个操作。
几个注意点
间隙锁在可重复读隔离级别下才有效
MySQL 中细粒度的锁有行锁、间隙锁、Next-Key Lock
一行数据可以加锁,数据之间的空隙也可以加锁,但是间隙锁之间不互斥,而是和插入数据这个操作互斥,也就是说加了间隙锁之后,往这个间隙中插入数据会被阻塞,直到间隙锁被释放了
锁是加在索引上的
如果用到覆盖索引,lock in share mode 只锁覆盖索引;for update 时,系统会认为接下来要更新数据,因此会顺便给主键索引上满足条件的行加上行锁;也就是说:如果要用 lock in share mode 来给行加读锁避免数据被更新的话,就必须得绕过覆盖索引的优化,在查询字段中加入索引中不存在的字段。
加锁规则:
加锁的基本单位是 next-key lock, next-key lock 是前开后闭的区间
查找过程中访问到的对象才会加锁
索引上的等值查询,给唯一索引加锁的时候,next-key lock 退化为行锁
索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock 退化为间隙锁
唯一索引上的范围查询会访问到不满足条件的第一个值为止
一些优化结论:
在删除数据的时候尽量加 limit, 不仅可以控制删除数据的条数,让操作更安全,还可以减小加锁的范围
事务锁类型
行锁
MySQL 的行锁有:行锁 (LOCK_REC_NOT_GAP)、间隙锁(LOCK_GAP)、Next-Key Lock
事务持久性
事务一致性
最后更新于