-
创建一张测试表
-
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 {
@Autowired
private AccountMapper accountMapper;
@Override
@Transactional
public 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 {
@Autowired
private AccountMapper accountMapper;
@Autowired
private BService bService;
@Override
@Transactional
public int updateUserBalance(Integer balance) {
accountMapper.updateUserBalance("A",balance);
try {
bService.updateUserBalance("B",balance);
}catch (Exception e){
log.info("更新BService异常:{}",e.getMessage());
}
return 1;
}
@Override
public int updateUserBalanceV2(Integer balance) {
return updateUserBalanceV3(balance);
}
@Override
@Transactional
public 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-only
at 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完成后,代理对象提交之前发现已经标记了回滚,则此时会进行全局回滚。
- 非代理对象测试
@Override
public int updateUserBalanceV2(Integer balance) {
return updateUserBalanceV3(balance);
}
@Override
@Transactional
public 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不是通过代理对象调用的。