【问题标题】:Synchronize changed entities in the same transaction在同一事务中同步更改的实体
【发布时间】:2020-04-27 08:51:17
【问题描述】:

我对更改实体并希望以其他方式更新它的事务方法有疑问。

首先,我使用 entitymanager 方法“get”从数据库中获取实体 A。 然后我得到一个相关实体 B 其中 A 到 B 是一对一的类型(可选)。 (所以 B 的 id 字段在 A 的表内)。现在我想通过服务方法删除实体 B。因此我必须使用 BID

在服务方法中,我从实体管理器(现在是 B')get B。然后我从获得的B'中得到A'。然后我删除 A'B' 的链接,当它通过 A'.setB(null) 后跟 serviceOfA .save(A').

然后我通过 serviceOfB.delete(B') 删除 B'

当通过 id 删除 B 的方法完成后,我想更改实例 A 的属性。 例如,创建另一个 B 实例。现在,当我再次通过 entitymanager get A 时,hibernate 会抛出一个 org.hibernate.exception.ConstraintViolationException 对象,该对象应该添加到新添加的 B'' 实例中到A。

我认为该问题与更改实例 A' 的删除方法有关,因此无法重新加载 A。但是我怎样才能重新加载 A 的新状态呢? 请看下面:

@Transactional
    public void compeleteSomething(
            @NonNull String location,
            @NonNull String nameOfA) throws SomeException{
        A a= serviceOfA.get(nameOfA);

        B b= a.getB();
        someService.removeBAndLinkToA(b.getId()); // <-- maybe here is the error

        B newInstanceOfB = someService.createBOn(location);
        someService.setBonA(serviceOfA.get(nameOfA), newInstanceOfB); // <-- serviceOfA.get() throws error

        [...]
    }

这里是someService.removeBAndLinkToA(#)的方法

@Transactional
    public void removeBAndLinkToA(
            @NonNull Long id) {
        B b = serviceOfB.get(id);

        A a = b.getA();
        if (a!= null) {
            a.setB(null);
            serviceOfA.save(a); // <-- This should cause the error?
        }

        serviceOfB.delete(b);
    }

如何避免这个问题? 非常感谢!

【问题讨论】:

    标签: java hibernate jpa transactions java-ee-8


    【解决方案1】:

    在事务中工作时,如果实体管理器被注入适当的范围,则预计它会处理所有的关系直到提交。您不需要在每一步都保存实体,也不需要从数据库中再次检索它:它的状态由 entitymanager 管理(没有双关语)。

    简而言之,您的 completeSomething 方法不需要调用另一个服务方法。只需制作 b.setA(null), a.setB(new B()) 并返回。一切都应该按预期工作:

    @Transactional
    public void completeSomething(String aId) {
        A a = entityManager.find(A.class, aId);
        B b = a.getB();
        a.setB(new B());
        b.setA(null);
    } // container should end transaction here, commiting changes to entities
    

    如果事务成功,容器将提交对实体的更改,并且更改将反映在数据库中,只要@PersistenceContext 具有 PersistenceContextType.TRANSACTION 类型,这是默认值。

    【讨论】:

    • 感谢您的回答。不幸的是,我必须使用 someService-Class 的方法——因为我不想多次重复那段代码。这是个问题吗?
    • 不,这不是问题,只要都属于同一个事务并且来自entitymanager的引用相同。如果您使用 entitymanager.merge 进行任何更改,请务必获取返回的引用以进行任何新更改。
    • 无法返回更改后的实体怎么办?
    • 您可以使用 entityManager refresh 方法。它应该选择实体的最新状态。
    • 所以即使我将实体保存在同一个事务中但使用不同的对象引用,刷新方法也会正确同步它们吗?国家不脏吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多