您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
Insight Mybatis JdbcTemplate 混合事务控制的实现
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
Insight Mybatis JdbcTemplate 混合事务控制的实现
京东物流质控队
2020-12-31
IP归属:未知
465480浏览
计算机编程
## 混合使用的背景 最近项目中需要引入工作流引擎,实现业务和流程设计、流转的解耦。 工作流流引擎选用的是snaker,轻量、易上手、可定制。访问数据库用的是JdbcTemplate 。 项目中原有的持久层框架是Mybatis。 这样就带来一个`问题:怎样保证业务逻辑(Mybatis) 和工作流流引擎(JdbcTemplate )处于事务控制中`,避免数据异常。 比如:业务单据创建成功后,审批流程启动。如果单据创建成功,审批流程启动异常,事务就应该回滚,否则就成僵尸单据了。 ## 混合事务控制的配置 ```xml <!-- 按照正常的Spring事务管理配置即可,黑魔法在框架的扩展上体现。 --> <tx:annotation-driven proxy-target-class="true" /> <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> ``` ## 混合事务控制的分析 首先,事务控制的原理是通过AOP进行事务增强,实现数据连接事务的开启、提交或者回滚。 然后,事务控制的核心是开启事务后,会把对应的Connection 关联到当前的线程中,所有关联的数据库操作,使用的都是这个Connection,才能保证逻辑事务的完整性。 所以,Mybatis 和JdbcTempate 混合事务控制,保证数据一致性,`关键就是保证不同框架获取到的是事务开启后的同一个Connection 对象`。剩下的就是AOP 拦截器实现提交或者回滚即可。 ## Insight Mybatis 事务的开启 **关键类**: org.mybatis.spring.transaction.SpringManagedTransactionFactory org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor **工作原理** ```java /** * 动态代理 SqlSession,拦截对应的方法,事务相关的操作托管给Spring's Transaction Manager * 通过这个InvocationHandler, 把所有的Mybatis 数据库操作的getSqlSession 都委托给Spring 处理,偷天换日。 * 核心实现: * 给当前线程绑定一个 SqlSession对象,这样就能够保证后续的持久化操作获取的都是这个 SqlSession对象。 */ private class SqlSessionInterceptor implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 从Spring事务管理器获取 sqlSession,或者在需要时创建一个新sqlSession。 // Retrieve a sqlSession for the given key that is bound to the current thread. // @see SqlSessionUtils#getSqlSession SqlSession sqlSession = getSqlSession(...); try { Object result = method.invoke(sqlSession, args); if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) { // force commit even on non-dirty sessions because some databases require // a commit/rollback before calling close() sqlSession.commit(true); } return result; } catch (Throwable t) { // ... } } } ``` ```java /** * 管理从Spring's transaction manager 获取的 connection * 如果事务管理是启用状态,那么commit/rollback/close 操作统一交给事务管理器去完成。 */ public class SpringManagedTransaction implements Transaction { @Override public Connection getConnection() throws SQLException { if (this.connection == null) { openConnection(); } return this.connection; } /** * Gets a connection from Spring transaction manager and discovers if this * {@code Transaction} should manage connection or let it to Spring. * <p> * It also reads autocommit setting because when using Spring Transaction MyBatis * thinks that autocommit is always false and will always call commit/rollback * so we need to no-op that calls. */ private void openConnection() throws SQLException { // 获取的Connection 操作,会检测是否启用了事务管理器。如果有事务管理器,会给当前线程绑定或者获取一个 Connection对象。 (Will bind a Connection to the thread if transaction synchronization is active) this.connection = DataSourceUtils.getConnection(this.dataSource); this.autoCommit = this.connection.getAutoCommit(); this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource); } } ``` ## Insight JdbcTempate 事务的开启 ```java public <T> T execute(CallableStatementCreator csc, CallableStatementCallback<T> action) { // 和Mybatis SpringManagedTransaction 获取Connection 调用同样的方法。 Connection con = DataSourceUtils.getConnection(getDataSource()); CallableStatement cs = null; try { cs = csc.createCallableStatement(conToUse); applyStatementSettings(cs); T result = action.doInCallableStatement(csToUse); handleWarnings(cs); return result; } catch (SQLException ex) { // ... } finally { JdbcUtils.closeStatement(cs); DataSourceUtils.releaseConnection(con, getDataSource()); } } ``` ## 总结 - `Mybatis JdbcTemplate 获取Connection 的方式殊途同归`,保证获取的是同一个 Connection。 - Mybatis 事务启用后,会给当前的线程注册两个对象,SqlSession 和 Connection。 - 如果Spring 事务是否启用的判断方式是根据`当前线程的ThreadLocal 是否有初始化`。 - 如果需要把事务托管给Spring,最简单的是通过 `DataSourceUtils.getConnection` 获取连接。 - 借鉴Spring 框架的集成Mybatis 的方式,为后续的通用设计提供参考。
原创文章,需联系作者,授权转载
上一篇:JUST技术: 使用 ClickHouse实现时序数据管理
下一篇:JUST技术:基于轨迹的新冠易感人群查询方案
相关文章
Taro小程序跨端开发入门实战
Flutter For Web实践
配运基础数据缓存瘦身实践
京东物流质控队
文章数
7
阅读量
22477
作者其他文章
01
Insight Mybatis JdbcTemplate 混合事务控制的实现
spring容器中mybatis和jdbcTemplate混合事务控制
01
Insight Spring Test 事务自动回滚的实现
了解Spring Test 事务控制的原理
01
Insight Mybatis 日志打印及使用建议
mybatis 利用动态代理实现日志原理分析
01
Insight Spring中的算法-占位符查找
spring框架中的字符串算法
京东物流质控队
文章数
7
阅读量
22477
作者其他文章
01
Insight Spring Test 事务自动回滚的实现
01
Insight Mybatis 日志打印及使用建议
01
Insight Spring中的算法-占位符查找
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号