Spring的setRollbackOnly()

在之前的文章中,我们讲过如果有两个事务,A和B,均是Required new的传递类型,而我们在A中调用B。如果B中抛出了异常(RuntimeException,Spring的事务机制只会补货RumtimeException),而A中将异常进行了catch,则A会抛出以下的错误

Exception in thread "main" org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

从而强制将事务进行回滚,Spring采用该机制是为了防止用户错误的将引发回滚的异常进行捕获而忘记继续抛出。
以下的例子展示了这种情况:

@Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void testTransaction() {
        LOGGER.info("start test transaction");
        CustApplyTicketService service = ApplicationContextHolder.getBean("transactionService",
                TransactionService.class);
        Person person = new Person();
        person.setName("测试");
        service.saveEntitySelective(ticket);
        try {
            service.testInnerTransaction();
        } catch (Exception e) {
            LOGGER.error("", e);
        }
        LOGGER.info("finish test transaction");
    }

    @Override
    @Transactional
    public void testInnerTransaction() {
        throw new RuntimeException("this is a inner exception");
    }

    public static void main(String[] args) {
            ApplicationContext ac = new ClassPathXmlApplicationContext("conf/applicationContext-test.xml");
            TransactionService service = ac.getBean("transactionService", TransactionService.class);
            service.testTransaction();
    }

那有的时候,我们有这种需求,我们就是希望A回滚,但是又不想通过这种方式抛出异常来进行。那有没有不抛出异常的回滚方式呢?
我们可以通过设置TransactionStatus的rollBackOnly标志位的方式来实现。
比如如下的方式:

@Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void testTransaction() {
        LOGGER.info("start test transaction");
        CustApplyTicketService service = ApplicationContextHolder.getBean("transactionService",
                TransactionService.class);
        Person person = new Person();
        person.setName("测试");
        service.saveEntitySelective(ticket);
        try {
            service.testInnerTransaction();
        } catch (Exception e) {
            LOGGER.error("", e);
           // 这部是关键
           TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        LOGGER.info("finish test transaction");
    }

    @Override
    @Transactional
    public void testInnerTransaction() {
        throw new RuntimeException("this is a inner exception");
    }

    public static void main(String[] args) {
            ApplicationContext ac = new ClassPathXmlApplicationContext("conf/applicationContext-test.xml");
            TransactionService service = ac.getBean("transactionService", TransactionService.class);
            service.testTransaction();
    }

在上面,我们并不会收到UnexpectedRollbackException的异常。而由于我们人工的设置了回滚标志,所以数据库仍会进行回滚。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,991评论 19 139
  • 光芒越来越近 你却越来越远 我们曾爱过 可是 曾经只是曾经 愿她一身婚纱 换你一世真心 我爱你
    姜大欣阅读 283评论 0 0
  • “我害怕一种固定而且重复的生活。“ “我害怕自己的生命在固定而且重复的生活中变成一种原地踏步的机械式的循环。” “...
    陈妥阅读 783评论 2 13
  • “临兵斗者,皆阵列在前!孔雀不动明王咒!“ 从小不是一个好学生,所以教材没有好好念,杂七杂八的书看了不少,尤其日本...
    本来源起阅读 421评论 0 51
  • 对于“界限感”,我觉得很容易被人忽视,不管是在家庭中还是职场里,“界限感”不清晰就会引发各类误会和矛盾。 ...
    方智永阅读 271评论 0 1