我们使用 Hibernate 3.5.6-Final 和 Hazelcast 3.6.1 二级缓存。
Parent
我在 a和Child
具有 Hibernate 设置的实体之间有双向、一对多的关系inverse = true
。实体类定义如下:
class Parent {
Set<Child> children;
... // setters, getters, other properties
}
class Child {
Parent parent;
... // setters, getters, other properties
}
Run Code Online (Sandbox Code Playgroud)
父级的 Hibernate 映射定义如下:
<set name="children"
lazy="true"
inverse="true"
cascade="all"
sort="unsorted">
<cache usage="read-write"/>
<key column="parent_id"/>
<one-to-many class="Child"/>
</set>
Run Code Online (Sandbox Code Playgroud)
子进程的 Hibernate 映射定义如下:
<many-to-one name="parent"
class="Parent"
cascade="none"
column="parent_id"
not-null="true"/>
Run Code Online (Sandbox Code Playgroud)
当前的代码现在添加 aChild
如下Parent
:
child.setParent(parent);
parent.getChildren().add(child);
Run Code Online (Sandbox Code Playgroud)
问题是第二行代码导致 Hibernate 加载所有子项。在我们的设置中,这是一个非常昂贵的操作,因为子实体具有急切集合,而子实体又具有急切集合的实体。
目前无法选择更改 Hibernate 模型。
我将上面的代码修改如下:
child.setParent(parent);
sessionFactory.getCache().evictCollection( "Parent.children", parent.getId() );
Run Code Online (Sandbox Code Playgroud)
到目前为止这有效。现在明显的问题是,如果在执行代码之前加载children
当前会话中的父级集合可能会过时。我想确保之后任何调用都会parent.getChildren()
返回最新的集合,而无需实际将子项显式添加到集合中。我实际上想告诉 Hibernate 使该集合无效,以便它在需要时再次加载该集合。
有一个更好的方法:
你需要让多对一的一方变得懒惰。
<many-to-one name="parent"
class="Parent"
cascade="none"
column="parent_id"
not-null="true"
lazy="true"/>
Run Code Online (Sandbox Code Playgroud)只要您不需要在当前运行的 Persistence Context 中获取 Parent 实体,您就可以只获取 Proxy 引用:
Parent parentProxy = session.load(Parent.class, parentId);
Run Code Online (Sandbox Code Playgroud)现在,您可以简单地创建一个新的子项,如下所示:
Child newChild = new Child();
child.setParent(parentProxy);
session.persist(newChild);
Run Code Online (Sandbox Code Playgroud)另一个解决方法如下:
您甚至不获取父代理引用,而是执行以下操作:
Parent parentReference = new Parent();
parentReference.setId(parentId);
Child newChild = new Child();
child.setParent(parentReference);
session.persist(newChild);
Run Code Online (Sandbox Code Playgroud)
这样,如果您只需要保留子实体,则无需完全获取父实体。
我找到了解决问题的方法。我通过添加一个新方法解决了addChild
这个问题,Parent
如下所示:
public void addChild(Child child) {
child.setParent(this);
if (Hibernate.isInitialized(getChildren()) {
getChildren().add(child);
} else {
Hibernate.getSessionFactory().getCache().evictCollection(
getClass().getName()+".children", this.getId());
}
}
Run Code Online (Sandbox Code Playgroud)
因此:如果由于某种原因已经加载了子项,则新的子项将添加到子项集中。这确保了已加载的集保持一致。如果该集合尚未加载,我只需将父级设置为子级并逐出二级缓存(此处描述了所需的操作: https: //github.com/hibernate/hibernate-orm/pull/580)。由于该集合尚未加载,因此也不会不一致。当之后访问该集合时,Hibernate 将加载该集合,包括新的子集合。
归档时间: |
|
查看次数: |
2871 次 |
最近记录: |