spring-kafka导致spring事务失效
发现问题
一个spring-boot工程,已经通过配置spring.kafka.producer.transactionIdPrefix开启KafkaTemplate的executeInTransaction事务功能。因为业务上需要发送kafka消息后同时更新数据库记录状态,结果发现单元测试跑完后数据库并不会回滚。
调试过程
- 测试类已经使用
-
123
@SpringBootTest
@RunWith
(SpringRunner.
class
)
@Transactional
进行标注,@Rollback标注在类上或者测试方法上均无效。
-
- 数据库操作的service方法已经标注@Transactional,在此方法内下断点,通过Evaluate Expression TransactionSynchronizationManager#isSynchronizationActive()发现结果是false
- 定位到
TransactionAspectSupport#determineTransactionManager
方法,发现此方法返回了一个类型为KafkaTransactionManager
的对象,至此问题初步定位为spring没有拿到正确的transcationManager
源码分析
查看KafkaAutoConfiguration发现注册了KafkaTransactionManager对象,这个类还继承了AbstractPlatformTransactionManager
因为项目使用的mybaits-plus,并配置了spring.datasource,没有使用hibernate。打开DataSourceTransactionManagerAutoConfiguration 发现默认的transactionManager注册条件是没有PlatformTransactionManager,而KafkaTransactionManager又正好是这个类型,所以这里根本不会注册。在注册transactionManager的方法里面下断点,果然不会进去。
Google搜索
搜索一下类似的问题,找到这个帖子https://stackoverflow.com/questions/47354521/transaction-synchronization-in-spring-kafka
解决问题
需要增加一个Configuration
- 是要解决DataSourceTransactionManagerAutoConfiguration默认不注册transactionManager的问题
- 是让transactionManager变成默认的事务管理器,免得在所有@Transactional指明事务管理器名称
- 是要增加一个chainedTransactionManager使得kafka和数据库操作同时在事务中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | @Configuration public class TransactionConfig { private final DataSource dataSource; private final TransactionManagerCustomizers transactionManagerCustomizers; TransactionConfig(DataSource dataSource, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) { this .dataSource = dataSource; this .transactionManagerCustomizers = transactionManagerCustomizers.getIfAvailable(); } @Bean //去掉了ConditionalOnMissingBean解决问题1 @Primary //解决问题2 public DataSourceTransactionManager transactionManager(DataSourceProperties properties) { DataSourceTransactionManager transactionManager = new DataSourceTransactionManager( this .dataSource); if ( this .transactionManagerCustomizers != null ) { this .transactionManagerCustomizers.customize(transactionManager); } return transactionManager; } @Bean //解决问题3 public ChainedKafkaTransactionManager chainedKafkaTransactionManager(DataSourceTransactionManager transactionManager, KafkaTransactionManager<?, ?> kafkaTransactionManager){ return new ChainedKafkaTransactionManager<>(transactionManager, kafkaTransactionManager); } } |
最后修改单元测试类(junit4)上的注解为:
1 2 3 | @SpringBootTest @RunWith (SpringRunner. class ) @Transactional (transactionManager = "chainedKafkaTransactionManager" ) |
当需要让kafka事务和JDBC事务处于同一级时使用 transactionManager = "chainedKafkaTransactionManager"
转自 https://blog.csdn.net/feg545/article/details/113742434
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构