您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
Insight Spring Test 事务自动回滚的实现
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
Insight Spring Test 事务自动回滚的实现
京东物流质控队
2021-01-05
IP归属:未知
179360浏览
计算机编程
## 测试环境事务控制的意义 - 避免测试用例的数据持久化的影响。需要事务控制回滚,还原场景,这样测试用例可以重复使用。(tests changes to the state may affect future tests) - 我们的业务逻辑需要事务控制,测试环境也要同样的模拟。 ## 测试环境-事务控制demo ```java /** * 只需要测试类添加@Transactional, 保证所有的测试方式都有事务控制,并且执行完成后自动回滚。 */ @RunWith(SpringRunner.class) @ContextConfiguration(classes = TestConfig.class) @Transactional public class HibernateUserRepositoryTests { @Test public void createUser() { // track initial state in test database: final int count = countRowsInTable("user"); User user = new User(...); repository.save(user); // Manual flush is required to avoid false positive in test sessionFactory.getCurrentSession().flush(); assertNumUsers(count + 1); // 方法执行完成后,insert user 会自动回滚,不会在数据库中添加脏数据 } } ``` ## 源码实现 ### 自动回滚的原理 Spring 采用容器注入的方式,`在Junit 测试框架的基础上`,引入TestExecutionListener 的概念,方便拓展自定义的事件。 事务控制就是基于这样的设计,通过`实现TestExecutionListener 接口,达到事务特性增强的目的`。 ```java /** * 支持Spring Test 事务控制实现的TestExecutionListener * * @see org.springframework.test.context.transaction.TransactionalTestExecutionListener */ public class TransactionalTestExecutionListener extends AbstractTestExecutionListener { /** * 如果是以事务的形式运行,那么会在测试方法执行前,开启事务 * 前提条件:有@Transactional 注解,并且容器中配置了TransactionManager。SpringBoot 不用考虑,使用Spring 框架的需要检查下是否有这个配置 <tx:annotation-driven transaction-manager="transactionManager"/> */ public void beforeTestMethod(TestContext testContext) throws Exception { final Method testMethod = testContext.getTestMethod(); // 如果是@NotTransactional,直接跳过 if (testMethod.isAnnotationPresent(NotTransactional.class)) { return; } // 检测当前的方法或者类是否需要事务、是否有配置TransactionManager PlatformTransactionManager tm = null; if (transactionAttribute != null) { tm = getTransactionManager(testContext, transactionAttribute.getQualifier()); } // 获取到tm,开启事务。按照惯例,缓存事务对象,方便afterTestMethod 进行事务继续操作。 if (tm != null) { TransactionContext txContext = new TransactionContext(tm, transactionAttribute); runBeforeTransactionMethods(testContext); // 复习下开启事务的过程:Check settings、check propagation、Acquire Connection、setAutoCommit(false)、Bind the session holder to the thread startNewTransaction(testContext, txContext); this.transactionContextCache.put(testMethod, txContext); } } public void afterTestMethod(TestContext testContext) throws Exception { Method testMethod = testContext.getTestMethod(); // If the transaction is still active... TransactionContext txContext = this.transactionContextCache.remove(testMethod); if (txContext != null && !txContext.transactionStatus.isCompleted()) { try { // rollback or commit endTransaction(testContext, txContext); } finally { runAfterTransactionMethods(testContext); } } } } ``` ### TestExecutionListener 注入的原理 在测试容器启动过程中,会检测当前的测试类是否有指定 TestExecutionListeners。如果没有就采用默认的TestExecutionListeners。 ```java /** * Determine the default TestExecutionListener classes. * 默认的TestExecutionListeners: * ServletTestExecutionListener * DependencyInjectionTestExecutionListener * TransactionalTestExecutionListener 就是本人啦! * @see org.springframework.test.context.TestContextManager */ protected Set<Class<? extends TestExecutionListener>> getDefaultTestExecutionListenerClasses() { Set<Class<? extends TestExecutionListener>> defaultListenerClasses = new LinkedHashSet<>(); for (String className : DEFAULT_TEST_EXECUTION_LISTENER_CLASS_NAMES) { try { defaultListenerClasses.add((Class<? extends TestExecutionListener>) getClass().getClassLoader().loadClass(className)); } catch (Throwable t) { } } return defaultListenerClasses; } ``` ## 涉及到注解 - @Transactional 启用事务控制必要注解。测试环境下,如果加在类上就全部生效,加载方法上只有方法生效。 - @TransactionConfiguration 配置事务测试的条件,如果有多个transactionManager 实例,需要这个注解。 - @BeforeTransaction @AfterTransaction 用于测试类的`方法注解,不受事务控制`。 - @NotTransactional 标识测试的方法不受事务控制,等同于上述的注解。 - @Rollback `自定义标识测试的方法是否要回滚`,用来避免默认情况下回滚的操作。 ## 总结 - Spring 托管一切,集成一切,包罗万象。各种集成的方案和实现都值得借鉴。 - 了解Spring Test 事务控制的原理,可以更好的编写测试用例,提升工作效率。
原创文章,需联系作者,授权转载
上一篇:凹凸技术揭秘·羚珑页面可视化·成长蜕变之路
下一篇:JUST技术:基于HMM的实时地图匹配项目
相关文章
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 Mybatis JdbcTemplate 混合事务控制的实现
01
Insight Mybatis 日志打印及使用建议
01
Insight Spring中的算法-占位符查找
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号