8

我有这个问题很长时间了,我已经搜索了网络和SO,但还没有找到解决方案。我希望你能帮助我。

我在两个实体之间有父子关系,如下所示:

@Entity
public class Parent {
    // ...

    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    private Set<Child> children = new HashSet<Child>();

    // ...
}

@Entity
public class Child {
    // ...

    @ManyToOne(fetch = FetchType.LAZY)
    private Parent parent;

    // ...
}

问题是当我创建一个新的孩子并将其分配给父母时,当它已经在缓存中时,父母不会得到更新。

 Parent parent = new Parent();
 em.persist(parent);

 // ...

 Child child = new Child();
 child.setParent(parent);
 em.persist(child);

 parent.getChildren().size(); // returns 0

我曾尝试使用@PreUpdate 在子项被持久化时自动将子项添加到父项,但是如果我们在 2 个不同的线程中有 2 个实体管理器(例如在 JBoss 中),问题仍然存在,直到我们调用em.refresh(parent)

所以问题是 - 有没有办法顺利消除问题并确保parent.getChildren()始终返回最新的孩子名单?

4

3 回答 3

8

大多数 ORM 都会以这种方式运行。

缓存中的对象不会从数据库中更新(不必要的额外读取)。还可以将对象模型和持久性视为分开的。即保持您的对象模型与自身一致,不要依赖持久性机制为您执行此操作。

因此,如果您希望将对象添加到集合中,请在“setParent”代码中执行此操作。

在这种情况下,最佳实践实际上是让关系的一方完成所有工作,让另一方推迟处理。另外我建议使用字段访问而不是方法访问​​,这样您就可以更灵活地自定义方法。

向父级添加一个名为 addChild 的方法

 public void addChild(Child child) {
    child.setParent0(this);
    getChildren().add(individualNeed);
 }

然后在 Child 中设置 setParent:

public void setParent(Parent parent) {
   parent.addChild(child);
}

Child 中的 setParent0 是 child 上 parent 的属性 stter。

public void setParent0(Parent parent) {
   this.parent = parent;
}

我还建议“getChildren”方法返回一个不可变的集合,这样开发人员就不会无意中不使用这个方法(我在所有这些中都学到了艰难的方法)。

还有一件事,你应该在上面的代码中有空检查代码和其他防御性部分,为了清楚起见,我把它省略了。

于 2009-07-30T14:42:41.783 回答
4

很确定您的问题是您的级联设置。

@Entity
public class Parent {
   // ...

   @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, 
      cascade = {CascadeType.REMOVE, CascadeType.PERSIST})
   @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
   private Set<Child> children = new HashSet<Child>();

   // ...
}

@Entity
public class Child {
    // ...

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
    private Parent parent;

    // ...
}

使用这些级联设置将级联持久化并更新到子对象。

例如。

Parent parent = new Parent();
em.persist(parent);

// ...

Child child = new Child();
child.setParent(parent);
em.persist(child); //will cascade update to parent

parent.getChildren().size(); // returns 1

或者

Parent parent = new Parent();
Child child = new Child();
parent.setChild(parent);
em.persist(parent); //will cascade update to child

child.getParent(); // returns the parent

更多信息可以在Hibernate Annotations中找到

于 2011-09-28T12:55:49.523 回答
1

关于缓存问题,当您有多个虚拟机针对具有单独缓存的同一数据库运行时,这是一个非常常见的问题。它被称为“缓存漂移”。

大多数对休眠友好的缓存实现(ehcache、OSCache 和 SwarmCache)都有内置的分布式缓存,可用于同步缓存。分布式缓存通常发送更新缓存状态的多播消息。例如,通过 SessionFactory.evict(Class,id) 执行二级缓存驱逐,将导致向集群中的其他缓存发送无效消息,这将使该对象在其他缓存中的任何其他副本无效。

根据您的部署,您可能接受也可能不接受多播。如果不是,您可能需要使用像 memcached 这样的单缓存解决方案。

我个人觉得eh cache的分布式缓存的配置非常简单。

EH 缓存在这里更详细地讨论了这个问题:http: //ehcache.org/documentation/distributed_caching.html

于 2010-11-16T17:03:06.700 回答