(1)前序:
多个事务同时更新一行数据,此时都会加锁,然后都会排队等待,必须一个事务执行完毕了,提交了,释放了锁,才能唤醒别的事务继续执行。那么多个事务运行的时候加的什么锁?
(2)独占锁:
也就是Exclude独占锁,当有一个事务加了独占锁之后,此时其他事务再要更新这行数据,都要加独占锁,但是只能生成独占锁在后面等待。那么有个问题,当有人更新数据的时候,其他事务事务可以读取这行数据嘛?默认情况下需要加锁嘛?
不用,因为默认情况下,有人更新数据的时候然后你去读取这行数据,直接默认就是开启MVCC机制,也就是说,此时对一行数据的读和写两个操作默认是不会加锁互斥的,因为MySQL设计mvcc机制就是为了这个问题避免频繁加锁,此时读取数据,完全可以根据ReadView,去在undo log版本连条里找一个你能读取的版本,完全不用顾虑别人在更新。
就算真的更新完毕还提交了,基于mvcc机制还是读不到更新的值,因为ReadView机制是不运行的,所以默认情况下的读,不需要加锁,不需要关心其他事务的更新加锁问题,基于mvcc机制读某个快照就可以了。
(3)假设你在查询时就是想要加锁呢?
那也是ok的,MySQL首先支持一种共享锁,就是S锁,这个共享锁的语法如下,select from table lock in share mode,在查询语句后面加上lock in share mode,意思就是查询的时候对一行数据加共享锁。
如果此时有别的事务在更新这行数据,已经加了独占锁,此时还能加共享锁嘛?是不行的,*共享锁和独占锁是互斥的,此时这个查询只能等着。
如果先加了共享锁,然后别人更新要加独占锁行吗?当然不行,此时锁是互斥的,只能等待。
如果在加共享锁的时候,别人也加了共享锁,这个是可以的,共享锁和共享锁是不会互斥的。
所以可以看出,更新数据的时候必然加上独占锁,独占锁和共享锁互斥,此时别人不能更新;但是此时要查询,默认是不加锁的,走mvcc机制读快照版本,但是查询手动加共享锁,共享锁和独占锁是互斥的,但是共享锁和共享锁是 不互斥的。
(4)查询加互斥锁:
一般开发业务系统,查询主动加共享锁,这种情况极为罕见,数据库的行锁是实用功能,但是一般不会在数据库层面做复杂的手动加锁操作,反而会用基于redis/zookeeper的分布式锁来控制业务系统的锁逻辑。
另外,查询操作还能加互斥锁,select * from table for update,这个意思是查出来数据以后还要更新,加独占锁了其他事务都不要更新这个数据了。一旦查询时候加了独占锁,此时事务提交之前,任何人都不能更新数据,只能在本事务里更新数据,等你提交了。别的事务再更新数据。
(5)默认情况下:
学习了 更新数据的走独占锁,查询数据的mvcc机制读快照,然后通过查询加共享锁和独占锁的方式,共享锁和独占锁之间存在互斥