【问题标题】:@Transactional not rolling back@Transactional 不回滚
【发布时间】:2016-03-04 03:12:03
【问题描述】:

一个@Transactional 方法调用另外两个方法,这两个方法也存在于@Transactional 方法中,但是当其中一个被调用方法出现异常时,事务应该回滚,它没有发生

-----The Main Transactional method-------------
@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = RestException.class)
    public BaseDto createFPSAndUser(FpsStoreDto fpsStoreDto){

        log.info("<--Starts FPSStoreService .createFPSAndUser-->"+fpsStoreDto);
        BaseDto baseDto = new BaseDto();
        try {
            UserDetailDto  userDetailDto = fpsStoreDto.getUserDetailDto();
            userDetailDto.setCreatedBy(fpsStoreDto.getCreatedBy());
            baseDto = createFPSStore(fpsStoreDto);
            if(baseDto.getStatusCode() != 0){
                throw new RestException(ErrorCodeDescription.getDescription(baseDto.getStatusCode()));

            }
            userDetailDto.setFpsStore(null);
            baseDto = userDetailService.createUserDetail(userDetailDto);
            if(baseDto.getStatusCode() != 0){
                throw new RestException(ErrorCodeDescription.getDescription(baseDto.getStatusCode()));
            }
            FPSStore fpsStore =  fpsStoreRepository.findByCode(fpsStoreDto.getCode());
            UserDetail userDetail = userDetailRepository.findByUserId(userDetailDto.getUserId());
            userDetail.setFpsStore(fpsStore);
            userDetailRepository.save(userDetail);
            baseDto.setStatusCode(0);
        } catch(RestException restException){
            log.info("RestException -:", restException);
            restException.printStackTrace();
            baseDto.setStatusCode(baseDto.getStatusCode());
        } catch (Exception exception) {
            log.info("Exception -:",exception);
            exception.printStackTrace();
            baseDto.setStatusCode(ErrorCodeDescription.ERROR_GENERIC.getErrorCode());
        }
        log.info("<--Ends FPSStoreService .createFPSAndUser-->"+baseDto);
        return baseDto;
    }

------------------Called method 1st-----------

@Transactional(propagation = Propagation.REQUIRED)
    public BaseDto createFPSStore(FpsStoreDto fpsStoreDto) {
    _________________________
    __________________________
    ________________________
 return baseDto;

}

------------------------2nd Transactional method-----
@Transactional(propagation = Propagation.REQUIRED)
    public BaseDto createUserDetail(UserDetailDto userDetaildto) {
_______________
_______________
_______________
return baseDto
}

【问题讨论】:

  • 这看起来像是您要求我们编写您的代码。 Stackoverflow 不是代码编写社区!另外请正确格式化您的代码!!!
  • 容易出错的代码和复杂的事务配置。另外,删除 rollBackFor 东西。
  • 嗨帕克哈罗。感谢您下次在病房中格式化代码的建议,我不会有机会问我这个问题。我问的不是代码的原因。请让我知道它为什么不起作用..因为我认为这个 stackoverflow 就是为了这个......
  • 谢谢我们是博格..
  • 这至少有 2 个问题,首先 spring 使用代理来应用 AOP,所以基本上内部方法调用上的 @Transactional 被忽略,接下来你会捕获所有异常,因此会触发 tx 代码从来没有看到它并认为一切都很好并且会提交。

标签: java spring jpa transactions


【解决方案1】:

您已经设置了rollbackFor=RestException.class,但是您的代码会捕获该异常并且不会重新抛出它。从 Spring 的角度来看,RestException 从未被方法抛出,也没有理由回滚事务。

如果您希望发生回滚,您需要在 catch 块的末尾执行 throw restException;

【讨论】:

  • 那么 rollBackFor 应该是什么?应该是rollBackfor = Exception.class
  • 不,@kayaman 说你不应该捕获“所有”异常来记录和设置状态码.. 如果你希望你的事务被回滚,你应该抛出 RestException
  • @DebendraParida rollbackFor 仅在异常被抛出方法时才会发生。您捕获异常并返回baseDto,因此即使在方法内部发生异常,Spring 也不会看到它,它正在从外部查看它.
  • @DebendraParida 当然它不起作用,因为你不明白你在做什么。我从来没有说过要删除rollbackFor
【解决方案2】:

你是在告诉 Spring 只有在

rollbackFor = RestException.class

但如果你发现异常

catch(RestException restException){

Spring 永远不会注意到抛出了异常。您需要删除您的 catch 块(两者)您可以在 catch 结束时抛出异常

    catch(RestException restException){
        log.info("RestException -:", restException);
        restException.printStackTrace();
        baseDto.setStatusCode(baseDto.getStatusCode());
        throw restException;
    }

【讨论】:

  • 我明白了你的意思,但问题是我必须返回出现故障原因的 BaseDto,所以如果我重新抛出 RestException,我的状态码将消失......无论如何,谢谢..
  • 您也可以使用 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 手动回滚事务这里有文档docs.spring.io/spring/docs/3.0.x/reference/…
  • 嗨,谢谢.. 我刚刚在我的异常块中使用了 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(),我的问题解决了,感谢大家的评论和建议
【解决方案3】:

@Transactional告诉容器(spring)处理注解方法调用的事务管理。

  • 这是使用代理完成的,请参阅understanding aop proxies,这意味着:
    • 注解仅适用于被注解对象的外部调用
    • 只有在方法边界之外抛出的异常才会被容器处理

`

  • 每个带注释的方法都有其own transaction logical context,这意味着:
    • 即使你的main方法有参数rollbackFor=RestException.class 内部的不会继承配置,并且在抛出休息异常时不会触发回滚
    • 如果内部方法由于在执行过程中抛出异常而触发回滚,即使调用者捕获到异常,事务也会回滚,随后每次访问数据库都会导致UnexpectedRollbackException

【讨论】:

    猜你喜欢
    • 2017-04-14
    • 1970-01-01
    • 1970-01-01
    • 2018-11-08
    • 1970-01-01
    • 1970-01-01
    • 2019-06-30
    • 2016-12-19
    相关资源
    最近更新 更多