MySQL的锁
写这篇的原因是自己在了解Spring事务的实现原理时,对程序执行结果的一些疑问,发觉自己对于MySQL的认识还是太片面了。
准备看一看《高性能MySQL》这本书,到时候对于MySQL的锁来一个总结
以下均基于MySQL8.0.19,Innodb引擎
从问题展开:
Q1
执行test方法,结果是什么?
执行流程分析:
- 首先开启test方法事务,执行update id 1,加意向排他锁与id为1这一行的排他锁,等待提交;
- 由于query方法的事务传播机制为REQUIRE_NEW,获取新的数据库连接,开启query方法事务,快照读,不加锁,查询id为1的结果为1000,提交事务。
- test方法结束,提交事务。
最终输出结果为1000,id为1的money更新为9000。
Q2
将Q1中query方法的事务传播机制改为REQUIRE,结果是什么
执行过程同1,区别在于所有操作在test方法的事务中,只有一个事务
执行结果同1
Q3
执行test方法,结果是什么?
执行流程分析:
- test方法事务开启,加意向锁排他锁与id为1这一行的排他锁,执行update语句,等待事务提交;
- query方法事务开启,尝试获取意向共享锁,检测到test方法事务持有意向排他锁,兼容,成功获取意向共享锁,执行select,尝试对id为1的行加共享锁,但是改行已有排他锁,query事务等待锁,阻塞;
- 由于query方法阻塞不结束,test方法事务无法commit,结果锁等待超时
执行结果就是超过Innodb设置的锁等待事件后,抛出
com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
下图为阻塞过程中查看innodb事务状态
Q4
在Q3的基础上,将update放在query之后,执行结果?
执行流程分析:
- test事务开启,无任何操作,不获取任何锁;
- query方法事务开启,加意向共享锁与id为1的共享锁,执行语句,提交,查询结果为1000,释放所有锁。
- test事务中,获取意向排他锁与id为1的排他锁,执行update,提交。
执行流程就是,先查询,后更新,两个事务不存在冲突情况。
未完待续。。。
Q.E.D.