当前位置: 首页 > 知识库问答 >
问题:

嵌套的@Transactional方法中的Spring UnexpectedRollbackException

颜昕
2023-03-14

我有一个dao类(myDAO),它用@transactionalannotaion(在类级别)标记,没有其他参数。在这个dao类中,我有一个方法,在某些情况下,它需要抛出一个已检查的异常并执行事务回滚。类似这样的事情:

@Transactional
public class MyDao {

    public void daoMethod() throws MyCheckedException() {

        if (somethingWrong) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new MyCheckedException("something wrong");
        }
}

这个很好用。但是,这个dao方法是从一个服务方法调用的,该服务方法也被标记为@transactional:

public class MyService {

    @Autowired
    private MyDao myDao;

    @Transactional
    public void serviceMethod() throws MyCheckedException {
        myDao.daoMethod();
    }

}

问题是,当从ServiceMethod()调用DAOMethod()并将事务标记为仅回滚时,我会得到一个UnexpectedRollbackException

Spring创建了两个事务拦截器:一个用于myDAO,一个用于myservice。当daomethod()事务标记为回滚时,mydao的拦截器执行回滚并返回。但随后堆栈移动到myservice的拦截器,该拦截器会发现之前的回滚,并抛出UnexpectedDrollBackException

一个解决方案是从MyDAO中删除@transactional注释。但是现在这是不可行的,因为mydao被用于很多地方,这可能会导致错误。

另一种解决方案是不将事务仅设置为daomethod()中的回滚,而是将serviceMethod()标记为在MyCheckedException上还原事务。但我不喜欢这个解决方案,因为我有很多这样的“服务方法”,我必须显式地标记所有这些方法,以便在该异常时回滚。而且,将来添加新服务方法的每个人都必须考虑到这一点,因此它为错误创造了机会。

有没有一种方法可以将事务设置为仅从daomethod()回滚,并防止Spring抛出UndependedRollbackException?例如,参数隔离传播的组合?

共有1个答案

程亦
2023-03-14

我想出来了。我还必须明确地告诉“外部”拦截器,我想回滚事务。换句话说,两个拦截器都需要被“通知”回滚的情况。这意味着在ServiceMethod()中捕获MyCheckedException并将事务状态设置为仅回滚,或者将ServiceMethod()标记为这样的@transactional(rollbackfor=MyCheckedException.class)

但正如我在OP中提到的,我想避免这样做,因为它很容易出错。另一种方法是默认情况下对MyCheckedException进行@transactional回滚。但那是完全不同的故事。

 类似资料:
  • 我将Spring与JPA一起使用。我打开了和。在我的用户注册服务方法中,我调用了一些其他服务方法,它们被注释为。这些方法可以做各种事情,比如发送欢迎电子邮件和在我们的第三方支付系统中注册新创建的用户。 一切都很好,直到我想验证第三方支付系统是否成功创建了用户。此时,方法试图创建一个(引用新创建的),并出现 寄存器调用如下所示: 支付服务调用以完成其注册用户的工作,如下所示: 这里列出的StackO

  • 问题内容: 是否可以在spring嵌套@Transactional带注释的方法?考虑这样的事情: 如果我在b()中回滚并在a()中回滚,在这种情况下会发生什么? 问题答案: 不需要 对方法的第二个注释,因为默认情况下 ,其传播为,因此由method调用的方法将是事务性的。如果要在通过method调用的方法中启动新事务,则需要修改传播规则。阅读有关交易传播的信息。

  • 问题内容: 在执行以下操作时,当我尝试访问延迟加载的异常时遇到错误: 我的实体看起来像这样: 我的印象是,通过在我的方法中使用@Transactional批注,它将使会话保持活动状态,直到该方法完成为止,从而使我可以访问延迟加载的Address集合。 我想念什么吗? 编辑 按照Tomasz的建议:在我的方法中,状态变为。 这确实可以缩小问题的范围,但是为什么此时我的“交易”不能处于活动状态? 问题

  • 问题内容: 我想在应用程序开始时阅读文本数据装置(CSV文件),并将其放入数据库中。 为此,我创建了带有初始化方法(@PostConstruct批注)的PopulationService。 我也希望它们在单个事务中执行,因此我在同一方法上添加了@Transactional。 然而,@Transactional似乎被忽略:该交易启动/停止我的低水平DAO方法。 那我需要手动管理交易吗? 问题答案:

  • 本文向大家介绍mysql中insert与select的嵌套使用方法,包括了mysql中insert与select的嵌套使用方法的使用技巧和注意事项,需要的朋友参考一下 本文讲述了mysql中insert与select的嵌套使用的方法,对于初学MySQL的朋友有一定的借鉴价值。 这里需要实现在mysql从多个表中组合字段然后插入到一个新表中,通过一条sql语句实现该功能需求。具体情形是:有三张表a、

  • 如何聚合一个值在嵌套在Elasticsearch嵌套位置?我对一个嵌套对象没有问题,但在嵌套对象内的嵌套我感到困惑... 样本数据: 欲望结果: 在索引映射中,我将cat_a和条目字段的类型设置为嵌套,当我从工具字段查询聚合时,在cat_a的根(级别1)中没有问题,并且可以工作,但是在聚合中在rx_a(这是在第2级)我不能检索结果,它或空或显示错误,因为我的错误查询。 查询级别1 agg: 如何处