添加Schedulers.boundedElastic的@JdbcTest测试运行失败是什么原因?
问题原因分析
- 核心根源是Spring的事务上下文是和线程绑定的,
@JdbcTest测试默认会为每个测试方法开启一个独立事务,测试执行完成后自动回滚,全程事务不会提交到数据库。 @Sql注解执行的建表、插入数据操作,都是在测试主线程绑定的事务中完成的,数据只在当前事务内可见,其他事务无法读取到未提交的这部分测试数据。
两个测试的执行逻辑差异如下:
foo测试中,Mono.fromCallable内的jdbcTemplate.queryForList是在测试主线程执行,能拿到当前绑定的事务连接,所以可以正常读到@Sql插入的2条数据,列表非空,测试通过。bar测试中添加的.publishOn(Schedulers.boundedElastic())会切换执行线程,导致jdbcTemplate实际执行查询时所在的线程不是测试主线程,无法获取到测试事务的绑定连接,会向连接池申请新的连接开启独立事务。这个新事务无法读取到测试主线程事务中未提交的插入数据,所以查询结果为空列表,触发断言失败。
解决方案
可根据实际需求选择任意一种方案:
- 若需要异步执行JDBC操作,可改用
subscribeOn(Schedulers.boundedElastic())同时配合Spring事务上下文传递逻辑,比如手动传递TransactionSynchronizationManager中的事务绑定信息。 - 测试侧快速修复方案:给测试类添加
@Rollback(false)注解,强制测试事务提交,这样其他事务也能读到测试数据,注意需要手动清理测试数据避免不同用例互相干扰。 - 也可以直接关闭测试方法的事务管理,添加
@Transactional(propagation = Propagation.NOT_SUPPORTED)注解,让@Sql的操作直接提交到数据库。
内容的提问来源于stack exchange,提问作者kokodyn
相关产品推荐
相关产品推荐

