https://www.cnblogs.com/leedaily/p/8378779.html
重点看这部分:
InnoDB的行锁模式及加锁方法
InnoDB实现了以下两种类型的行锁。
- 共享锁(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上的锁。
排他锁指的是一个事务在一行数据加上排他锁后,其他事务不能再在其上加其他的任何锁(读锁和写锁)。mysql InnoDB引擎默认的修改数据语句:update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型,如果加排他锁可以使用select …for update语句,加共享锁可以使用select … lock in share mode语句。所以加过排他锁的数据行在其他事务种是不能修改数据的,也不能通过for update和lock in share mode锁的方式查询数据,但可以直接通过select …from…查询数据,因为普通查询没有任何锁机制。
另外需要说明一下,mysql innodb采用mvcc版本控制的方式。。。update的写锁是加在旧版本记录上。具体参考这篇文章https://blog.csdn.net/qq_41388308/article/details/88583968最后一段话。我复制到下面:
事务1开启事务,先进行一个查询操作:
事务2开启(还未提交),并且对行进行更新操作:
事务1也对这行进行更新操作:
我们发现这里出现了一个问题,就是并不能进行更新操作,错误提示是获取锁超时。
为什么会出现上面的问题呢?
前面我们讲到了update操作会对操作行进行加锁操作,所以事务2使用update操作会新增一个行并且对原来那行进行修改删除版本号并且进行一个加锁操作,而事务1使用update操作也是新增一个行并且对原来那行进行一样的操作,加锁和修改删除版本号,但是现在有个问题,事务2的锁还没交出来,事务1怎么去进行加锁和修改版本号操作呢。因为这个问题所以就引发了上面那个获取不到锁的问题。只有事务2commit了,事务1才能获取到或者锁。同理两个事务进行delete同一行的操作也会引发同样的问题。(个人理解应该是这个原因,有错欢迎指正,网上也没有找到说法)这里也可以理解为insert、update和delete会更新版本号,是当前读(当前版本)。所以update,insert,delete操作都是依据当前最新版本号来进行的。
注意:
以下为猜测:
新增的数据在事务未提交之前还不会保存当前版本号,当事务提交时,则把当前事务版本号保存到新增记录的隐藏列中