12

我需要使用 EJB 3、Hibernate、Spring Data 和 Oracle 进行大规模插入。最初,我使用的是 Spring Data,代码如下:

talaoAITDAO.save(taloes);

其中 talaoAITDAO 是 Spring Data JpaRepository子类,而 taloes 是 TalaoAIT 实体的集合。在该实体中,其各自的 ID 具有以下形式:

@Id
@Column(name = "ID_TALAO_AIT")
@SequenceGenerator(name = "SQ_TALAO_AIT", sequenceName = "SQ_TALAO_AIT", allocationSize = 1000)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SQ_TALAO_AIT")
private Long id;

此外,该实体没有相关实体可进行级联插入。

我的问题是,所有实体都是单独插入的(例如INSERT INTO TABLE(col1, col2) VALUES (val1, val2))。有时,它可能会导致超时,并且所有插入都将回滚。我希望将这些单独的插入转换为批量插入(例如INSERT INTO TABLE(col1, col2) VALUES (val11, val12), (val21, val22), (val31, val32), ...)。

研究提高性能的替代方案,我在 hibernate 文档中找到了这个页面,超出了 Hibernate 批量大小混淆这个其他页面。基于它们,我编写了以下代码:

Session session = super.getEntityManager().unwrap(Session.class);
int batchSize = 1000;
for (int i = 0; i < taloes.size(); i++) {
    TalaoAIT talaoAIT = taloes.get(i);
    session.save(talaoAIT);
    if(i % batchSize == 0) {
        session.flush();
        session.clear();
    }
    taloes.add(talaoAIT);
}
session.flush();
session.clear();

此外,在 peristence.xml 中,我添加了以下属性:

<property name="hibernate.jdbc.batch_size" value="1000" />
<property name="order_inserts" value="true" />

然而,尽管在我的测试中我发现了一个细微的差异(主要是大集合和大批量),但它并没有想象中那么大。在日志控制台中,我看到 Hibernate 继续进行单独的插入,而不是替换它们以进行大量插入。在我的实体中,我使用的是序列生成器,我相信这不是问题(根据 Hibernate 文档,如果我使用身份生成器,我会遇到问题)。

所以,我的问题是这里可能缺少什么。一些配置?有些方法没用过?

谢谢,

拉斐尔·阿方索。

4

3 回答 3

16

有几件事。

首先你的配置属性order_inserts一定是错误的hibernate.order_inserts。目前您的设置被忽略并且您没有更改任何内容。

接下来使用EntityManager代替做所有讨厌的休眠的东西。EntityManager也有一个andflush方法clear。这至少应该清理你的方法。如果没有顺序,这有助于清理会话并防止对其中的所有对象进行脏检查。

EntityManager em = getEntityManager();
int batchSize = 1000;
for (int i = 0; i < taloes.size(); i++) {
    TalaoAIT talaoAIT = taloes.get(i);
    em.persist(talaoAIT);
    if(i % batchSize == 0) {
        em.flush();
        em.clear();
    }
    taloes.add(talaoAIT);
}
em.flush();
em.clear();

接下来你不应该让你的批次变大,因为这会导致内存问题,从 50 之类的开始并测试哪个/什么表现最好。有时脏检查将花费更多时间,然后对数据库进行刷新和清除。你想找到这个甜蜜点。

于 2013-11-29T12:48:35.830 回答
1

persistence.xml如果我在我的 JPA文件中设置了以下 Hibernate 属性,M. Deinum 发布的解决方案对我来说非常有用:

<property name="hibernate.jdbc.batch_size" value="50" />
<property name="hibernate.jdbc.batch_versioned_data" value="true" />
<property name="hibernate.order_inserts" value="true" />
<property name="hibernate.order_updates" value="true" />
<property name="hibernate.cache.use_second_level_cache" value="false" />
<property name="hibernate.connection.autocommit" value="false" />

我使用的是 Oracle 数据库,所以我也定义了这个:

<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
于 2017-02-09T18:29:46.803 回答
0

我最近发现了一个很有前途的小型库,用于使用 Hibernate 和 Postgresql 批量插入。它被称为踏板方言并使用 Postgresql - 命令COPY,许多人声称该命令比批量插入快得多(参考:Postgresql 手册Postgresql 插入策略 - 性能测试复制如何工作以及为什么它比批量插入快得多插入?)。踏板方言允许使用COPY而不会完全失去 Hibernate 的易用性。您仍然可以获得实体和行的自动映射,而不必自己实现它。

于 2018-07-26T14:52:53.340 回答