原文发布于:http://www.gufeng.tech/  谷风的个人主页

      这是工作中遇到的一个真实问题的处理过程,如果对分析过程不感兴趣,可以直接跳到最后看最终方案。

      我们在持久化这一层,并没有用任何的ORM框架(无论是Hibernate还是MyBatis,亦或是DBUtils),而是采用了在JDBCTemplate基础上进行了简单的包装,同时我们也决定将AutoCommit设置为True,在sql语句执行完成后立即提交。这样做相比于@Transactional注解或者通过AOP来控制事务性能更好,也更方便。

      在评估了优劣之后,便开始使用这种方式,随之我们也遇到了一个真实的问题。这里我们把涉及公司的信息全部隐藏掉,简化后的需求是:一个业务要连续执行两个表的insert操作,必须保证同时生效或失败。当然采用补偿的方式也能达到效果,但是考虑到我们的用户量不是十分巨大,而且未来一段时间内用户不会暴增,采用补偿有点得不偿失,所以决定在特定情况下采用手动控制事务,其余情况默认AutoCommit为True。在定了这个目标之后,开始研究如果在JDBCTemplate基础上实现。

      首先尝试的是获得Connection,并设置AutoCommit为False,代码如下:

DataSource dataSource = ((JdbcTemplate)namedParameterJdbcTemplate.getJdbcOperations()).getDataSource();
Connection connection = DataSourceUtils.getConnection(dataSource);
connection.setAutoCommit(false);

      设置之后,测试发现并不生效,此时已经知道这么做是没有用的。接下来我们进一步分析,看在JDBCTemplate中是如何获得数据库连接的,可以通过打断点的方式查看,每次获得的connection对象的hashCode不一致。


      我们知道NamedParameterJdbcTemplate这个类持有一个JdbcTemplate的实例,我们从NamedParameterJdbcTemplate的update方法逐层跟进去,发现最终调用的是Jd