摘要
工作中有使用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
排查中有两个问题先要明确
- session嵌套是开了几个事务?
- 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
网友评论