Spring Boot集成MyBatis事务无法回滚问题求助
从你的描述来看,核心问题是Spring的@Transactional注解在Wildfly 9容器里没正确触发回滚——哪怕抛出了RuntimeException或者手动设置了回滚标记,数据还是被提交了。结合你的技术栈(Spring Boot 2.1.8 + Wildfly 9 + MyBatis),我梳理了几个最可能的原因和对应的解决步骤:
1. 容器接管数据源导致Spring事务管理器失效
Wildfly作为Java EE容器,会自动识别并管理数据源,很可能覆盖了你在application.properties里配置的Spring Boot数据源。这时候Spring默认的DataSourceTransactionManager(本地事务管理器)根本控制不了容器管理的数据源,事务实际由Wildfly的JTA事务管理器接管,但Spring的@Transactional注解没和容器的事务系统正确绑定,自然不会触发回滚。
解决方法:
有两种思路可选:
- 适配容器的JTA事务:在Spring Boot里配置
JtaTransactionManager,让Spring事务和Wildfly的JTA机制对接。新增一个配置类:
@Configuration public class TransactionConfig { @Bean public PlatformTransactionManager transactionManager() { return new JtaTransactionManager(); } }
- 禁止容器接管数据源:在项目的
WEB-INF目录下创建jboss-deployment-structure.xml,阻止Wildfly干预你的数据源配置:
<jboss-deployment-structure> <deployment> <exclude-subsystems> <subsystem name="datasources"/> </exclude-subsystems> </deployment> </jboss-deployment-structure>
这样Spring Boot就能完全掌控自己配置的数据源,用本地事务管理器处理事务。
2. 检查@EnableTransactionManagement的代理模式
默认情况下,@EnableTransactionManagement用JDK动态代理,只对接口生效。你的MyService是普通类而非接口,虽然Spring Boot默认会 fallback 到CGLIB代理,但如果项目里有其他框架的代理(比如AOP相关),可能会导致事务切面没正确织入。
解决方法:
修改@EnableTransactionManagement注解,强制使用CGLIB代理:
@SpringBootApplication @EnableTransactionManagement(proxyTargetClass = true) @ComponentScan("my.package") public class ServletInitializer extends SpringBootServletInitializer { // 原有代码保持不变 }
3. 开启事务调试日志排查细节
要搞清楚事务到底有没有被创建、有没有触发回滚,最直接的方式是开Spring事务的DEBUG日志。在你的日志配置(比如logback.xml或log4j.properties)里加这段配置:
<!-- Logback示例配置 --> <logger name="org.springframework.transaction" level="DEBUG"/> <logger name="org.springframework.jdbc.datasource.DataSourceTransactionManager" level="DEBUG"/>
跑测试之后看日志:如果看不到Creating new transaction with name [my.package.MyService.doTask]或者Initiating transaction rollback这类日志,说明事务切面根本没生效;如果有回滚日志但数据还是提交了,那基本可以确定是数据源被容器接管的问题。
4. 确认MyBatis与Spring事务的绑定
虽然你用了mybatis-spring-boot-starter,自动配置应该能把MyBatis和Spring事务绑定,但还是可以额外检查两点:
- 确保你的
MyMapper接口加了@Mapper注解,或者在mybatis-config.xml里正确配置了mapper扫描路径; - 可以显式声明
SqlSessionFactory,确保它用的是Spring管理的数据源:
@Configuration public class MyBatisConfig { @Autowired private DataSource dataSource; @Bean public SqlSessionFactory sqlSessionFactory() throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource); sessionFactory.setConfigLocation(new ClassPathResource("mybatis-config.xml")); return sessionFactory.getObject(); } }
5. 显式指定事务传播行为
虽然默认的Propagation.REQUIRED传播行为是没问题的,但可以尝试显式指定,确保事务被正确创建:
@Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED) public void doTask() { // 原有业务代码不变 }
按照上面的步骤逐一排查,应该能解决事务不回滚的问题。
内容的提问来源于stack exchange,提问作者Raj

