Spring Boot 2.0.1事务回滚失效问题求助
问题描述
我正在使用Spring Boot(v2.0.1.RELEASE)结合EntityManager开发,已经花费一周时间处理MySQL数据库异常时的事务回滚问题,但始终无法解决。执行saveUser方法时,虽然抛出了ServiceException,但用户仍然被保存到数据库;当把@Transactional的传播级别改为Propagation.MANDATORY时,直接报错提示没有现有事务。
相关代码
DAO层实现
@Repository public class HibernateDaoImp implements Dao { @PersistenceContext private EntityManager entityManager; public <T extends AbstractEntity> T saveOrUpdate(T entity) { if(entity.getId() == null || entity.getId().equals(0)) { this.entityManager.persist(entity); t = entity; } else { t = (T) this.entityManager.merge(entity); } return t; } }
Service层实现
@Service("userService") public class UserServiceImp implements UserService { @Autowired protected Dao dao; @Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {ServiceException.class}) public User saveUser(User user) throws ServiceException { user = this.dao.saveOrUpdate(user); throw new ServiceException(500, "internal error"); } }
修改传播级别后的注解
@Transactional(propagation = Propagation.MANDATORY, rollbackFor = {ServiceException.class})
日志与错误信息
执行saveUser的关键日志
2018-05-25 10:36:46.297 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : 为线程[http-nio-8080-exec-4]绑定键[org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3dd8ed71]对应的值[org.springframework.orm.jpa.EntityManagerHolder@4c6ea9e2]
2018-05-25 10:36:46.356 DEBUG 25041 --- [nio-8080-exec-4] c.s.knected.controller.UserController : save id=null
2018-05-25 10:36:46.357 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : 从线程[http-nio-8080-exec-4]获取键[org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3dd8ed71]对应的值[org.springframework.orm.jpa.EntityManagerHolder@4c6ea9e2]
2018-05-25 10:36:46.358 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : 为线程[http-nio-8080-exec-4]绑定键[HikariDataSource (HikariPool-1)]对应的值[org.springframework.jdbc.datasource.ConnectionHolder@5b4dc571]
2018-05-25 10:36:46.358 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : 初始化事务同步
2018-05-25 10:36:46.358 TRACE 25041 --- [nio-8080-exec-4] o.s.t.i.TransactionInterceptor : 获取[c.s.k.service.UserServiceImp.saveUser]的事务
2018-05-25 10:36:46.358 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : 从线程[http-nio-8080-exec-4]获取键[org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3dd8ed71]对应的值[org.springframework.orm.jpa.EntityManagerHolder@4c6ea9e2]
Hibernate: insert into user (created_by, time_created, deleted, deleted_by, time_deleted, name, time_updated, updated_by, adress, code, email, password, first_name, lost_login, last_name, mobile, phone, photo_id, time_registered, user_type) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'a')
2018-05-25 10:36:46.457 TRACE 25041 --- [nio-8080-exec-4] o.s.t.i.TransactionInterceptor : 完成[c.s.k.service.UserServiceImp.saveInvite]的事务,已抛出异常c.s.k.service.ServiceException
2018-05-25 10:36:46.457 TRACE 25041 --- [nio-8080-exec-4] o.s.t.i.RuleBasedTransactionAttribute : 应用规则判断事务是否应因c.s.k.service.ServiceException回滚
2018-05-25 10:36:46.457 TRACE 25041 --- [nio-8080-exec-4] o.s.t.i.RuleBasedTransactionAttribute : 生效的回滚规则为:匹配[c.s.k.service.ServiceException]的RollbackRuleAttribute
2018-05-25 10:36:46.460 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : 清除事务同步
2018-05-25 10:36:46.460 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : 从线程[http-nio-8080-exec-4]移除键[HikariDataSource (HikariPool-1)]对应的值[org.springframework.jdbc.datasource.ConnectionHolder@5b4dc571]
2018-05-25 10:36:46.468 TRACE 25041 --- [nio-8080-exec-4] .s.t.s.TransactionSynchronizationManager : 从线程[http-nio-8080-exec-4]移除键[org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@3dd8ed71]对应的值[org.springframework.orm.jpa.EntityManagerHolder@4c6ea9e2]
改为MANDATORY传播级别时的错误
org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
POM配置片段
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties>
问题分析与解决方案
从你的日志和代码来看,核心问题是事务代理未生效或事务未正确绑定EntityManager,以下是具体排查方向和解决步骤:
1. 确保事务管理被正确启用
虽然Spring Boot默认会自动配置事务管理,但在自定义EntityManagerFactory等场景下,需要显式开启事务管理。在你的Spring Boot启动类上添加@EnableTransactionManagement注解:
@SpringBootApplication @EnableTransactionManagement public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }
2. 检查事务代理是否生效
改为MANDATORY传播级别时报错,说明@Transactional注解没有被Spring解析,事务代理未创建。常见原因:
- 服务类未被Spring容器管理:确认
UserServiceImp的包被启动类的组件扫描覆盖,且没有通过new关键字手动创建实例。 - 方法访问权限问题:Spring动态代理无法代理
private或final方法,你的saveUser是public的没问题,但要避免同类方法内部调用(会绕过代理)。
3. 验证EntityManager与事务的绑定
显式指定EntityManager的事务上下文类型,确保它和当前事务绑定:
@PersistenceContext(type = PersistenceContextType.TRANSACTION) private EntityManager entityManager;
4. 检查MySQL数据库的事务支持
MyISAM引擎不支持事务,即使配置了回滚也不会生效。执行以下SQL确认表引擎:
SHOW CREATE TABLE user;
如果是MyISAM,修改为InnoDB:
ALTER TABLE user ENGINE=InnoDB;
5. 确认JPA依赖与配置完整性
检查POM是否包含spring-boot-starter-data-jpa依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
同时确认application.properties中的JPA配置正确:
spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect spring.jpa.show-sql=true spring.transaction.default-timeout=60
6. 验证异常类型匹配
确保抛出的ServiceException是你在rollbackFor中指定的类,避免出现同名类或子类导致的匹配失败。
快速验证步骤
- 给启动类添加
@EnableTransactionManagement注解。 - 确认MySQL表引擎为InnoDB。
- 直接通过Spring容器获取
UserService实例调用saveUser,避免同类内部调用。
按照以上步骤排查,应该能解决事务回滚失效的问题。
内容的提问来源于stack exchange,提问作者zjda

