对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X),通过上节的了解,只有加了X锁的事务可读可写,其他事务不能读不能写,我们来模拟验证下。
1)模拟的方式,开启两个cmd窗口,就代表同时有两个客户端(session)连接MySQL服务。当前的隔离级别是“RR(Repeatable Read)”,MySQL默认的“可重读”。
2)进入测试数据库,开启事务,(左边)先执行一条普通不加锁的select语句,然后(右边)紧跟着执行同样的select语句。
两边都能正常获取数据,因为都是不加锁的SQL语句,所以相互不影响。
3)接下来(左边)先执行select加X锁,然后再执行(右边)的语句。
(左边)select语句执行正常,看(右边)普通的select语句是成功的,可加锁的select语句执行后没有反应,直接卡那了,过一会就会报错:
锁等待超时。因为(右边)想要获取相同数据集的排他锁,(左边)占着一直获取不到,一定时间后就会超时。
通过上面的例子,是否可以感觉到锁的存在。
4)(左边)的事务楠神还没有提交,排他锁依然存在,楠神在(右边)再执行一个更新操作。
update语句自带排他锁功能,同样获取不到X锁报超时错误。
5)(右边)重新执行下update语句,(左边)commit提交
(右边)update语句还是卡在那,当(左边)commit一提交,(右边)立马就获取到了X锁,OK,更新成功。
6)(右边)更新完数据后,事务暂时没有提交,楠神在(左边)暂时不开启事务,执行下普通的select查询
咦?(右边)明明把“age”改成55了,怎么还是34。
7)(右边)提交下事务,然后(左边)再执行下select语句
这次是55了。所以说一个事务(A)未提交,其他事务是看不到(A)事务修改的数据的。
8)左右两边都再同时开启事务,执行select语句
9)(左边)先执行update语句,(右边)再执行加了X锁的select语句,(左边)提交
(右边)虽然身在事务中,可加了X锁select还是可以获取到(左边)提交事务后获取的数据。
10)假如说同样的条件下,(右边)未提交事务前最后一步执行的是普通select语句:
还是44,然后楠神在接着执行加X锁的和普通的select语句
哈哈,是不是这个地方很困惑。
普通的select语句满足了“可重复读”,也就是只要是事务没有结束,同样的普通select语句不论什么时候读取的数据都是一致的(前提是在此事务内没有对相关的数据做修改,其他事务修改了相关数据不受影响),加了锁(X锁、S锁)的select语句就不一样了,获取的数据都是最新的。