MySQL的锁

写这篇的原因是自己在了解Spring事务的实现原理时,对程序执行结果的一些疑问,发觉自己对于MySQL的认识还是太片面了。

准备看一看《高性能MySQL》这本书,到时候对于MySQL的锁来一个总结

以下均基于MySQL8.0.19,Innodb引擎
从问题展开:

Q1

q1.png
执行test方法,结果是什么?

执行流程分析:

  1. 首先开启test方法事务,执行update id 1,加意向排他锁与id为1这一行的排他锁,等待提交;
  2. 由于query方法的事务传播机制为REQUIRE_NEW,获取新的数据库连接,开启query方法事务,快照读,不加锁,查询id为1的结果为1000,提交事务。
  3. test方法结束,提交事务。

最终输出结果为1000,id为1的money更新为9000。

Q2

将Q1中query方法的事务传播机制改为REQUIRE,结果是什么

执行过程同1,区别在于所有操作在test方法的事务中,只有一个事务
执行结果同1

Q3

q3.png

执行test方法,结果是什么?

执行流程分析:

  1. test方法事务开启,加意向锁排他锁与id为1这一行的排他锁,执行update语句,等待事务提交;
  2. query方法事务开启,尝试获取意向共享锁,检测到test方法事务持有意向排他锁,兼容,成功获取意向共享锁,执行select,尝试对id为1的行加共享锁,但是改行已有排他锁,query事务等待锁,阻塞;
  3. 由于query方法阻塞不结束,test方法事务无法commit,结果锁等待超时

执行结果就是超过Innodb设置的锁等待事件后,抛出

com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

下图为阻塞过程中查看innodb事务状态
r3.png

Q4

在Q3的基础上,将update放在query之后,执行结果?

执行流程分析:

  1. test事务开启,无任何操作,不获取任何锁;
  2. query方法事务开启,加意向共享锁与id为1的共享锁,执行语句,提交,查询结果为1000,释放所有锁。
  3. test事务中,获取意向排他锁与id为1的排他锁,执行update,提交。

执行流程就是,先查询,后更新,两个事务不存在冲突情况。

未完待续。。。

Q.E.D.


一切很好,不缺烦恼。