Java 大量插入JPA+;冬眠

Java 大量插入JPA+;冬眠,java,hibernate,jpa,batch-insert,Java,Hibernate,Jpa,Batch Insert,我需要使用EJB3、Hibernate、Spring数据和Oracle进行大规模插入。最初,我使用的是Spring数据,代码如下: talaoAITDAO.save(taloes); 其中,talaoAITDAO是Spring数据子类,taloes是TalaoAIT实体的集合。在该实体中,其各自的ID具有以下形式: @Id @Column(name = "ID_TALAO_AIT") @SequenceGenerator(name = "SQ_TALAO_AIT", sequenceName

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

talaoAITDAO.save(taloes);
其中,talaoAITDAO是Spring数据子类,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)值(val1,val2)
)。有时,它会导致超时,所有插入都将回滚。我希望在批插入中转换这些单独的插入(例如
INSERT到表(col1,col2)值(val11,val12),(val21,val22),(val31,val32),…

我在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();
Session Session=super.getEntityManager().unwrap(Session.class);
int batchSize=1000;
对于(int i=0;i
另外,在peristence.xml中,我添加了以下属性:

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

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

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

谢谢

拉斐尔·阿方索。

有几件事

首先,您的配置属性错误
order\u inserts
必须是
hibernate.order\u inserts
。当前,您的设置被忽略,并且您没有更改任何内容

接下来使用
EntityManager
,而不是做那些讨厌的休眠工作。
EntityManager
还有一个
flush
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();
EntityManager em=getEntityManager();
int batchSize=1000;
对于(int i=0;i

接下来,你不应该让你的批量过大,因为这会导致内存问题,从50开始,测试哪个/什么性能最好。在这一点上,脏检查将花费比刷新和清除数据库更多的时间。您希望找到这个最佳点。

如果我在JPA
persistence.xml
文件中设置了以下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" />


我最近发现了一个很有前途的小型库,用于使用Hibernate和Postgresql对插入进行批处理。它被调用并使用Postgresql-command
COPY
,许多人声称它比批插入快得多(参考文献:,)。踏板方言允许使用
COPY
,而不会完全失去Hibernate的易用性。您仍然可以自动映射实体和行,而不必自己实现

为什么要展开
会话
?您可以直接在
entityManager
上执行
flush()
clear()
。但是:通常用java做大的插入是错误的;将所有内容转储到文件,将其传输到目标服务器并进行批量加载通常效果更好。也就是说,有时候您实际上需要在代码中进行一些转换;这可能是其中一种情况,我会首先将批量大小缩减到更合理的大小(比如50)。然后为hibernate启用调试日志记录,看看发生了什么。还要确保您有一个支持批量更新的数据库(和JDBC驱动程序)。您使用的是哪个数据库和hibernate版本?如果我没记错,那么即使使用了BulkInsert,您也会在日志中找到每个实体的单个insert语句。如果启用,您应该会看到有关批更新的一些特殊信息。类似于“[AbstractBatcher]执行批处理大小:5”和“[Expectations]批处理更新成功未知:0”的内容。Deinium:我正在oracle 11.2中使用Hibernate 4.1.9。关于序列,正如我在SequenceGenerator中定义的allocationSize为1000,它将每1000次插入调用一次?我有同样的问题,我已经正确地更新了每个配置,但仍然是spring数据jpa生成多个insert语句。事实上,编写一个batchsize在20到50之间的循环,并在该循环中执行“刷新”和“清除”。另外,hibernate属性应该是相同的批处理大小:如何获得entityManager?当我尝试刷新时,我一直收到一个javax.persistence.TransactionRequiredException错误。因此,起初我尝试使用@PersistentContext EntityManager EntityManager连接实体管理器,但后来不允许使用共享实体管理器刷新。所以我在这里遵循了一个解决方案,它只是挂起