【问题标题】:spring boot @transactional true if succeededspring boot @transactional 如果成功则为 true
【发布时间】:2019-06-18 16:51:48
【问题描述】:

我正在使用带有 spring boot 的 spring 4,我需要使用 @transactional。 如果我错了,请纠正我 - @transactional 使我的函数在与数据库的 1 个事务中运行,因此如果出现问题,该函数将执行回滚并且数据库中不会发生任何变化,否则它将提交。

我需要同时更新 4 行(来自 4 个不同的表),如果其中一个无法更新,我需要回滚。 所以在我的服务中我有这个功能:

@Transactional
public void updateDB(entity1, entity2, entity3, entity 4) {
    save(entity1);
    save(entity2);
    save(entity3);
    save(entity4);
}

现在我希望我的函数在事务以提交结束时返回 true,否则我希望它返回 false。 有什么办法吗?

【问题讨论】:

  • 使保存函数返回 true 并使用它。如果您使用的是弹簧数据save(),那么它们已经应该使用了。

标签: java spring spring-boot


【解决方案1】:

为了清楚起见:

在其默认配置中,Spring 框架的事务 基础设施代码仅在这种情况下将事务标记为回滚 运行时,未经检查的异常。也就是当抛出异常 是 RuntimeException 的实例或子类。 (错误实例 此外,默认情况下,会导致回滚)。检查的异常是 从事务方法抛出不会导致回滚 默认配置。

请注意,您可以使用@TransactionalrollbackFor 属性回滚业务异常,例如:

@Transactionl(rollBackFor=MyBusinessException.class)
public boolean myTransactionalMethod(){
 // stuff here
}

对于您想要的,只需在方法 updateDB 结束时返回 true :

@Transactional
public boolean updateDB(entity1, entity2, entity3, entity 4) {
    save(entity1);
    save(entity2);
    save(entity3);
    save(entity4);
    return true;
}

如果它不返回 true 则意味着您的事务已回滚

PS:来自spring documentation的另一条笔记

在代理模式下(默认),只有外部方法调用 通过代理进来的被拦截。这意味着 自调用(实际上,目标对象中的一个方法调用 目标对象的另一种方法)不会导致实际 即使调用的方法标记为 @事务。此外,代理必须完全初始化以提供 预期的行为,所以你不应该在你的 初始化代码(即@PostConstruct)。

【讨论】:

  • 但是如果发生异常不会返回false
  • @Janar 你说得对,我不会返回false 明确! ,我们可以在updateDB == trueupdateDB != true上测试
【解决方案2】:

您可以通过多种方式实现它,一种非常简单的方式可能是在最后返回 true 实际上只有当您的方法以 return 指令结束时您才能获得结果并且事务管理器将向您保证事务已完成并且所有的保存都在同一个事务中。

但是请!请注意,如果 save(entity) 方法属于 updateDB(....) 的同一类,即使您的类或方法标有 @Transaction,保存也不会在事务中。这是与 Spring 自动代理相关的 Spring 的一个棘手“功能”。神奇的 Transaction 被触发和传播,因为您的类被包装到代理 Spring 为您管理事务的代理。这对于 Spring bean 来说是正确的,它在 bean 创建生命周期中被必要的组件代理。但是,如果在您的 @Transactional 类 A 中调用 A 类的其他方法,则您的服务调用不会从代理传递,并且第二个服务调用不在事务中。

我举个例子:

@Transactional
class A {


    public Entity save(Entity e) {
        .....
    }

    public Entity update(Entity e) {
        .....
        // the save method is not proxed becouse it is callled from the current instance and not
        // form the proxed spring bean instance
        save(e);
        ...
    }
}



@Transactional
class SaveA {


    public Entity save(Entity e) {
.....
    }


}

@Transactional
class UpdateA {


    private final SaveA saveA;

    UpdateA(SaveA saveA) {
        this.saveA = saveA;
    }

    public Entity update(Entity e) {
        .....
        // the save method is proxed becouse it is called from saveA that is a proxed bean
        saveA.save(e);
        ...
    }

}

【讨论】:

  • 他也可以用 Transactional 注释 save 方法,而无需将 save 方法放在另一个用 @Transactional 注释的类上!
  • 不,不幸的是不是真的,我这样说是出于我的个人经验!!!!!!
  • 我记得很好地调试了在这种情况下不会触发 TransactionalAdvice 的 spring 代码。
  • 好吧,可能我的解释不好,我想我会尽量详细说明并尽快回复
  • 你上次的更新证实了我的想法.....很明显我已经解释了我的想法
【解决方案3】:

很难做到这一点。实际提交发生在@Transactional 下的方法返回之后。例如,数据库需要做的一些检查是在数据写入表时完成的。例如,只有在数据写入磁盘时才会捕获数据库上的约束违规。到那时,该方法已经返回。因此,即使您从方法返回状态,您也会遇到当数据库由于某些错误执行回滚时您的方法返回成功的情况。

【讨论】:

    猜你喜欢
    • 2021-03-20
    • 2020-04-13
    • 1970-01-01
    • 1970-01-01
    • 2019-02-04
    • 1970-01-01
    • 2018-11-08
    • 2020-02-03
    • 1970-01-01
    相关资源
    最近更新 更多