-
创建一张测试表
-
AccountMapper
public interface AccountMapper {@Update("update account set balance = #{balance} where username = #{username}")int updateUserBalance(@Param("username") String username, @Param("balance") Integer balance);
}
- BService接口与实现类
public interface BService {int updateUserBalance(@Param("username") String username, @Param("balance") Integer balance);}@Service
public class BServiceImpl implements BService {@Autowiredprivate AccountMapper accountMapper;@Override@Transactionalpublic int updateUserBalance(String username, Integer balance) {int res = accountMapper.updateUserBalance(username, balance);throw new RuntimeException("更新" + username + "异常!");}}
- AService与实现
public interface AService {int updateUserBalance( @Param("balance") Integer balance);int updateUserBalanceV2(Integer balance);int updateUserBalanceV3(Integer balance);
}@Slf4j
@Service
public class AServiceImpl implements AService {@Autowiredprivate AccountMapper accountMapper;@Autowiredprivate BService bService;@Override@Transactionalpublic int updateUserBalance(Integer balance) {accountMapper.updateUserBalance("A",balance);try {bService.updateUserBalance("B",balance);}catch (Exception e){log.info("更新BService异常:{}",e.getMessage());}return 1;}@Overridepublic int updateUserBalanceV2(Integer balance) {return updateUserBalanceV3(balance);}@Override@Transactionalpublic int updateUserBalanceV3(Integer balance) {accountMapper.updateUserBalance("A",balance);accountMapper.updateUserBalance("A",balance);return 1;}}
- 测试类
@MapperScan(basePackages = "com.test.mapper")
@SpringBootApplication
public class CloudApplication {public static void main(String[] args) throws Exception {ConfigurableApplicationContext context = SpringApplication.run(CloudApplication.class, args);AService aService = context.getBean(AService.class);aService.updateUserBalance(90);}}
事务测试
- 多事务异常捕获测试
AService调用BService,此时BService是开启了事务的,BService抛出了异常,虽然AService捕获了异常,但此时A和B都可以回滚成功。
2025-01-08 11:39:19.936 INFO 21812 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2025-01-08 11:39:20.025 INFO 21812 --- [ main] c.sci99.cloud.service.impl.AServiceImpl : 更新BService异常:更新B异常!
Exception in thread "main" org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-onlyat org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:870)at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:707)at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:633)at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:386)at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)at com.sci99.cloud.service.impl.AServiceImpl$$EnhancerBySpringCGLIB$$48c3527b.updateUserBalance(<generated>)at com.sci99.cloud.CloudApplication.main(CloudApplication.java:21)
Transaction rolled back because it has been marked as rollback-only。
都可以回滚成功,因为BService也是一个代理的对象,在BService的updateUserBalance方法执行完成后,代理对象发现当前已存在一个事务,并且使用了默认的事务传播行为,代理对象捕获了异常,并将当前事务标记为了异常回滚,做完这一步操作之后会继续向上抛出异常。
AService执行updateUserBalance完成后,代理对象提交之前发现已经标记了回滚,则此时会进行全局回滚。
- 非代理对象测试
@Overridepublic int updateUserBalanceV2(Integer balance) {return updateUserBalanceV3(balance);}@Override@Transactionalpublic int updateUserBalanceV3(Integer balance) {accountMapper.updateUserBalance("A",balance);accountMapper.updateUserBalance("A",balance);return 1;}
public static void main(String[] args) throws Exception {ConfigurableApplicationContext context = SpringApplication.run(CloudApplication.class, args);AService aService = context.getBean(AService.class);//aService.updateUserBalance(90);aService.updateUserBalanceV2(90);}
通过AService直接调用代理对象的updateUserBalanceV2方法,
但是updateUserBalanceV2是没有开启事务的,在V2内调用了V3,此时事务是不会生效的,因为V3不是通过代理对象调用的。