mysql 锁机制
转自 https://www.jianshu.com/p/ed896335b3b4
共享锁&排它锁
innodb 实现的行级锁:
共享锁(S Lock):允许事务读一条数据
排它锁(X Lock):允许事务删除或跟新一条数据
锁兼容:只有两个共享锁
innodb默认情况下对select操作使用一致性非锁定读。
但是某些情况下,需要对select显示加锁
共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE
意向锁
意向锁:innodb支持多粒度锁定,允许行锁和表锁同时存在,不同粒度的加锁方式,成为意向锁。
意向共享锁(IS Lock):一个事务想获得一个表中某几行共享锁。
意向排它锁(IX lock):一个事务想获得一个表中的某几行排它锁。
乐观锁和悲观锁
乐观锁
读取数据认为别人不会修改,所以不加锁,在更新操作时判断一下在此期间别人有没有修改数据。
乐观锁实现方式
version:
在表中加一个数据库版本号(数字类型) 字段,读的时候连同version字段一同读出,更新的时候判断version条件等于刚读出的version,并对其+1. 如果不相等,则认为失败,不提交更新。
同理,时间戳字段也适用。
注意:读写分离情况下,存在同步延迟问题,此时要强制读master。
悲观锁
每次更新操作过程使数据处于锁定状态,一般使用数据库锁机制。
悲观锁的实现方式
可以通过innodb的排它锁实现:select ... for update.
锁问题
脏读
脏读和脏页不同。
脏页
脏页:在缓冲池中已经被修改的页,但是还没有刷新到磁盘,即内存和磁盘中的数据是不一致的,当然在刷新到磁盘之前,数据都写入到重做日志中了。
脏数据
指的是在缓冲区被修改的数据,但是还没有被提交。
脏读
就是指在不同事务下,读到其他事务未提交的数据,即读到脏数据。
不可重复读
也称提交读,就是一个事务能读到其他事务提交的数据。这造成一个事务两次读的数据可能不一致。
innodb通过next-key lock 算法来解决不可重复读。官方文档将不可重复读称为幻读。在next-key算法下,对于索引的扫描,不仅锁住扫描到的索引,还会锁住索引覆盖的范围(gap)。因此避免其他事务在这个范围内插入数据导致的幻读问题。
死锁
两个事务都等对方先释放。
回滚
innodb事务根据information_schema.INNODB_TRX表的trx_weight 事务权重(代表事务锁住的行数) 选择值较小的回滚。
锁的命令
1. 查看当前请求锁的信息:
show engine innodb status\G;
2. 事务表 information_schema.INNODB_TRX
3. 事务的锁表 information_schema.INNODB_LOCKS
4. 事务阻塞等待表 information_schema.INNODB_LCOK_WAITS