【mybatis】mybatis JDBC事务细节

版权声明:本文为原创文章,转载时请注明出处;文章如有错漏,烦请不吝指正,谢谢! https://blog.csdn.net/reliveIT/article/details/48145865

一、JDBC事务铺垫

    在JDBC事务操作中,conn.commit()和conn.setAutocommit(true)拥有相同的数据库操作效果,都会提交事务持久化对数据库的更改,这一点随便写个JDBC基本操作的demo就能够得到验证。


二、mybatis DQL

    查看mybatis openSession的源码,除非传入boolean autoCommit=true,否则默认都是false。

    因此mybatis的事务机制,无论是查询还是增删改,默认都会执行conn.setAutocommit(false),这句话会导致数据库关闭自动提交和开启事务(基本的JDBC demo已验证);在SqlSession关闭的时候会conn.setAutocommit(true),这里会提交事务。在使用基本的mybatis query的时候,最后是需要关闭SqlSession,如果忘记了这一步,在连接池机制下,会造成事务泄露,也就是说conn没有关闭,但是conn的事务一直没有提交。


三、mybatis DML

    DML也会默认conn.setAutocommit(false),但是mybatis的DML需要显示的SqlSession.commit(),否则在close的时候会回滚事务。这个细节的实现在于SqlSession中的一个标志位boolean dirty,这个标志位在SqlSession初始化的时候默认为false,在进行DML的时候会赋值为true,当commit的时候,再次被修改成false,close的时候会检查该标志位,如果为true,则会回滚事务,否则关闭连接(重置autocommit=true,连接池机制下是还会连接池)。

    也就是说,如果不commit,则不会持久化数据库操作,在SqlSession close的时候,回滚事务,然后重置autocommit=true,然后关闭连接;如果commit,但是没有close,那么提交了事务,但是没有把连接还会连接池,这样的失误会在连接池popConnection的时候得到补救(请查看源码逻辑);如果既没有commit,也没有close,则会造成事务泄露。


四、总结

    A. 对于DQL,你得session.close(),否则事物泄露;

    session.close()方法会提交事务和关闭连接,搭配dirty标志可以控制事物是否回滚;在整个DQL过程中,dirty标志位始终没有更改,一直都是false,因此在close的时候并不会回滚,在关闭连接的时候,会根据连接池类型将连接设置回自动提交;而DML则没有必要commit事物,因为标志位dirty为false,因此不会提交事务,则session.commit()方法是否调用并无必要。

    B. 对于DML,没有commit和close,则事物不提交、连接不关闭,有commit没有close,则事物提交但是连接泄露,有close没有commit,则事务回滚;

扫描二维码关注公众号,回复: 3499241 查看本文章

    当进行DML的时候,dirty标志位会修改为true;在进行事务提交的时候,会connection.commit(),向数据库提交事务,然后将dirty标志位修改为false;此时在进行事物关闭dirty=false则不会导致回滚,并在事物关闭的同时根据连接池类型将连接重置或关闭或还回池中;倘若没有commit,则会导致事务回滚;倘若没有close,则会导致事物和连接泄露。

    当然,在xml文件中配置数据源的时候,有一个超时的配置(当type=POOLED或其他数据源的配置),当采用POOLED的时候,其默认超时是protected int poolMaximumCheckoutTime = 20000,即20s过期,因此连接泄露的最小时间是20s。


附注:

    本文如有错漏,烦请不吝指正,谢谢!

猜你喜欢

转载自blog.csdn.net/reliveIT/article/details/48145865