同一方法调用中能否多次使用@Transactional注解?
事务管理问题分析与解决方案
首先,你当前的写法有两个核心问题:
- Spring的
@Transactional注解对私有方法完全无效:Spring事务依赖动态代理实现,私有方法无法被代理类拦截,所以update1和update2上的事务注解根本不会生效,两次更新会处于同一个默认事务中(如果updateData所在类被Spring管理的话),不会分别提交。 - 代码里update1的参数名写错了(
kesy→keys),会导致编译错误,记得修正。
你想要每次更新后提交并获取最新数据的需求,可以通过以下两种方案实现:
方案一:编程式事务(推荐,更灵活可控)
直接手动控制事务的提交与刷新,确保每次更新后立即同步到数据库:
@Autowired private PlatformTransactionManager transactionManager; @Override public void updateData(Keys keys) { // 处理第一个更新事务 TransactionStatus status1 = transactionManager.getTransaction(new DefaultTransactionDefinition()); try { if(StringUtils.isNotBlank(keys.getValue1())) { repo.updateKey1(keys.getValue1()); } transactionManager.commit(status1); // 若用JPA/Hibernate,刷新会话确保后续能拿到最新数据 if(repo instanceof JpaRepository) { ((JpaRepository<?, ?>) repo).flush(); } } catch (Exception e) { transactionManager.rollback(status1); throw e; } // 处理第二个更新事务 TransactionStatus status2 = transactionManager.getTransaction(new DefaultTransactionDefinition()); try { if(StringUtils.isNotBlank(keys.getValue2())) { repo.updateKey2(keys.getValue2()); } transactionManager.commit(status2); if(repo instanceof JpaRepository) { ((JpaRepository<?, ?>) repo).flush(); } } catch (Exception e) { transactionManager.rollback(status2); throw e; } }
方案二:声明式事务(需调整方法可见性)
把私有方法改为public,并用REQUIRES_NEW传播属性开启新事务,同时通过Spring代理对象调用方法(不能直接this.xxx调用,否则不会触发代理):
// 注入自身的Spring代理对象 @Autowired private YourService selfProxy; @Override public void updateData(Keys keys) { selfProxy.update1(keys); selfProxy.update2(keys); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void update1(Keys keys) { if(StringUtils.isNotBlank(keys.getValue1())) { repo.updateKey1(keys.getValue1()); } } @Transactional(propagation = Propagation.REQUIRES_NEW) public void update2(Keys keys) { if(StringUtils.isNotBlank(keys.getValue2())) { repo.updateKey2(keys.getValue2()); } }
Propagation.REQUIRES_NEW会强制开启一个独立的新事务,当前事务(如果存在)会被挂起,新事务提交后,后续操作能直接拿到数据库的最新数据。
额外提醒
- 同一列多次更新要注意并发问题:如果有其他线程同时修改该列,即便分两次提交,也可能出现数据覆盖,建议加乐观锁(比如给表加版本号字段)。
- 若使用MyBatis,事务提交后无需额外刷新,直接查询就能拿到最新数据;JPA/Hibernate则需要调用
flush()确保会话同步。
内容的提问来源于stack exchange,提问作者user2108383
相关产品推荐
相关产品推荐

