Mybatis SqlSession嵌套使用bug

摘要

工作中有使用Mybatis,碰到一种情况。

try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false)) {
   //dao delete from t1 where jid = 2; ----dao1
   //dao insert into t1(sid, jid) where jid=2; --dao2
   session.flushstatement --flush1
   try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false))  {
     //dao insert into t1() ---dao3 
     session.flushstatement --- flush2
   }
}
这样使用在flush2的时候,mysql报错,lock wait time out

排查中有两个问题先要明确

  1. session嵌套是开了几个事务?
  2. sql哪里锁住了?

开了几个事务?

参考http://blog.csdn.net/hupanfeng/article/details/9238127 分析Mybatis源码,可以发现一个session 对应着一个连接MySQL连接,所以嵌套的session应该是两个事务。并且batchexcutor模式下,session.flushstatement的时候,才会去写入mysql io中,也就是执行flush的时候,才会在mysql server端查询到该事务。

MySQL事务提交

同时MySQL中也不存在事务嵌套的说法,其事务提交的情况说明如下:

autocommit

autocommit是对于一个连接session来说,默认情况下,一个新的session里,autocommit=1;

autocommit=1时候,
如果没有begin, 一条sql语句就是一个事务,即任务要么被提交、要么失败回滚。
如果有begin,则无视了autocommit设置,走begin显式事务的规则。

autocommit=0时候,
则即使你不显示得begin,你的sql也在begin块里,即已经处在一个事务里了。
完全按照begin开始的事务的方式处理。

begin-commit

begin:
begin ----------- 1
sql1
sql2
sql3
commit --------------- 2
这是一个标准的显式事务块。

除去autocommit=1一条sql组成一个事务块之外
但是在某些情况下1,2都可以不显式的标识。
事务开始:
begin,
autocomit=0 ,当前不在事务中则默认开启一个事务

事务commit:
commit
一些mysql规定的语句,如begin等。e Section 14.3.3, “Statements That Cause an Implicit Commit”.

MySQL卡在哪里

所以刚两个事务卡在哪里了?

session 1 session2
begin
delete from t1 where jid = 2
insert into t1 values(2,3)
begin
insert into t1 values(2,4)
lock time wait out

事务1 在索引上2上删除了数据,导致锁住next-key锁,
事务2 在索引2上插入,需要访问next-key ,锁超时,事务失败。
具体参见超赞的博文:http://tech.meituan.com/innodb-lock.html

你可能感兴趣的:(Mybatis SqlSession嵌套使用bug)