以块的形式存储大数据:Hibernate @OneToMany关系

时间:2011-07-24 19:12:26

标签: hibernate jpa batch-file

我一直在使用Hibernate使用@OneToMany与@JoinColumn存储父子关系已经有一段时间了,它运行得很好。

但是现在我已经达到了一个对象的总大小太大而不适合记忆的程度。 (例如,现在有300万个儿童记录)。记录都存储在一个文件中,然后在被休眠之前解析为Java对象。

我想“分块”或“批量”记录,这样我一次只需要将其中的一小部分读入内存。我的方法类似于“加载10,000个子对象的集合,持久化到数据库(在父obj上调用'update'),清空子集合以释放RAM,重复”。

我想要这样工作:

Iteration 1:  Chunk1 (records 1-10,000) stored
Iteration 2:  Chunk2 (records 10,001-20,000) stored
Iteration 3:  Chunk3 (records 20,001-30,000) stored
etc

这是我遇到麻烦的地方。我保存的集合随着每次迭代而变化,这会导致hibernate在保存新子节点之前删除所有旧子节点。我最终没有得到我的所有部分,而是

Iteration 1: Chunk1 stored
Iteration 2: Chunk1 objects deleted, Chunk 2 stored
Iteration 3: Chunk2 objects deleted, Chunk 3 stored
etc

所以最后,只保存了我的最后一块。

有没有办法改变这种行为?我已经阅读过有关JDBC批处理的内容,但这并不是我正在寻找的内容。我也尝试分别存储每个Child,而不是通过“更新”到父级,但是当我这样做时,子记录被持久化而没有指向父级的指针。

更新

感谢快速而极好的回应。这种关系不是双向的 - 我会尝试这样做。我有遗留代码,不会与架构更改配合,因此有点受限制。

由于

1 个答案:

答案 0 :(得分:2)

这里的主要问题是:你的关系是双向的吗?也就是说,你在孩子那边有一个@ManyToOne指向父母吗?

如果你这样做,那种关系需要由孩子一方拥有:

// in Parent
@OneToMany(mappedBy="parent")
List<Child> getChildren();

// in Child
@ManyToOne
Parent getParent();

当以这种方式设置时, NOT 需要加载父集合中的所有(或任何)子项 - 您可以改为加载(或创建)子项,设置父项结束并拯救他们;你当然可以批量做。

如果您的关系双向,那么根据您的问题,它由父母拥有 - 您需要将其设为双向,如上所示(或单向,但与现在相反 - 见下文。

在一个单独的说明中,你甚至需要在父方面@OneToMany吗?有300万儿童记录,我无法想象它在哪里有用。