事务的回滚与失效行为

  • 创建一张测试表
    在这里插入图片描述

  • 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不是通过代理对象调用的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值