从源代码中知道真正的SqlSessionFactory使用的是 org.apache.ibatis.session.defaults.DefaultSqlSessionFactory的实例,同时,事务管理使用 org.mybatis.spring.transaction.SpringManagedTransactionFactory。但是在代码1的配置中,还添加了Spring事务管理的配置,就是在某个Service方法(或某个其他可被扫描到的方法)上加上 @Transactional注解,那么Spring的事务管理会自动创建事务,那么它和MyBatis的事务之间是怎么协作的呢?
可以看到在代码6中的方法 isSqlSessionTransactional(),它会返回上层代码中是否有Spring的事务,如果有,将不会执行下边的 commit()。在我的项目中的实际情况是没有Spring事务,所以肯定是走到了下面的 commit(),这个方法最终落到了 SpringManagedTransactionFactory中的 commit(),看代码:
//代码7 private void openConnection() throws SQLException { this.connection = DataSourceUtils.getConnection(this.dataSource); this.autoCommit = this.connection.getAutoCommit(); this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource); } public void commit() throws SQLException { if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Committing JDBC Connection [" + this.connection + "]"); } this.connection.commit(); } }可以看到,此处是否要执行 commit()操作是由3个变量决定的,如果DataSource的 autoCommit是 false,则其结果一定为 true,控制台也会看到一行日志: Committing JDBC Connection [xxxxxx],刚好与项目中遇到的情况相同。这个提交动作是需要和数据库交互的,比较耗时。
实验验证由上一节分析得出,造成DAO方法执行时间变长的原因是会多执行一次提交,那么如果上层方法被Spring事务管理器托管(或者数据源的 defaultAutoCommit为 true,这个条件已经在刚开始的问题重现被验证),则不会执行MyBatis的提交动作,DAO方法应该相应的执行时间会变短。于是将Service方法加上 @transactional注解,分别测试 true和 false的情况。结果:
可以看到执行的时间已经基本接近,由此基本可以确定是这个原因造成的。这里仍然有几个疑点,尤其是问题重现时没有出现2倍的时间消耗,如果你有别的想法,也欢迎提出来讨论。
Linux公社的RSS地址:https://www.linuxidc.com/rssFeed.aspx