使用 JPA/EJB3 进行批量插入
Posted
技术标签:
【中文标题】使用 JPA/EJB3 进行批量插入【英文标题】:Batch inserts with JPA/EJB3 【发布时间】:2010-10-01 16:22:11 【问题描述】:JPA/EJB3 框架是否提供标准方式来执行批量插入操作...? 我们使用hibernate作为持久化框架,所以我可以回退到Hibernate Session并使用组合session.save()/session.flush()实现批量插入。但是想知道 EJB3 是否支持这个...
【问题讨论】:
【参考方案1】:JPA 和 Hibernate 都没有为批量插入提供特别的支持,使用 JPA 进行批量插入的习惯用法与使用 Hibernate 相同:
EntityManager em = ...;
EntityTransaction tx = em.getTransaction();
tx.begin();
for ( int i=0; i<100000; i++ )
Customer customer = new Customer(.....);
em.persist(customer);
if ( i % 20 == 0 ) //20, same as the JDBC batch size
//flush a batch of inserts and release memory:
em.flush();
em.clear();
tx.commit();
session.close();
在这种情况下使用 Hibernate 的专有 API 并没有提供任何 IMO 优势。
参考文献
JPA 1.0 规范 第 4.10 节“批量更新和删除操作” Hibernate Core 参考指南 Chapter 13. Batch processing【讨论】:
只是为了进行完整性检查,您的if
语句应该是 i > 0 && i % 20 == 0
否则它会在添加第一个元素后立即刷新(并清除)。【参考方案2】:
具体针对hibernate,全程chapter 13 of the core manual讲解方法。
但是你说你想要通过 Hibernate 的 EJB 方法,所以实体管理器文档也有一章关于 here。我建议您同时阅读(核心和实体管理器)。
在 EJB 中,它只是关于使用 EJB-QL(有一些限制)。如果您需要更多灵活性,Hibernate 会提供更多机制。
【讨论】:
【参考方案3】:对于中等记录数,您可以这样使用:
em.getTransaction().begin();
for (int i = 1; i <= 100000; i++)
Point point = new Point(i, i);
em.persist(point);
if ((i % 10000) == 0)
em.flush();
em.clear();
em.getTransaction().commit();
但如果记录数很大,您应该在多个事务中执行此任务:
em.getTransaction().begin();
for (int i = 1; i <= 1000000; i++)
Point point = new Point(i, i);
em.persist(point);
if ((i % 10000) == 0)
em.getTransaction().commit();
em.clear();
em.getTransaction().begin();
em.getTransaction().commit();
参考:JPA Batch Store
【讨论】:
【参考方案4】:是的,如果您愿意,您可以回滚到您的 JPA 实现以获得您定义的控制。
JPA 1.0 对 EL-HQL 的支持很丰富,但对 Criteria API 的支持比较少,不过这已在 2.0 中得到解决。
Session session = (Session) entityManager.getDelegate();
session.setFlushMode(FlushMode.MANUAL);
【讨论】:
【参考方案5】:帕斯卡
在您插入 100000 条记录的示例中,它是在单个事务中完成的,因为 commit() 仅在最后被调用。它会给数据库带来很大压力吗?再者,万一有回滚,代价也太大了..
下面的方法会更好吗?
EntityManager em = ...;
for ( int i=0; i<100000; i++ )
if(!em.getTransaction().isActive())
em.getTransaction().begin();
Customer customer = new Customer(.....);
em.persist(customer);
if ((i+1) % 20 == 0 ) //20, same as the JDBC batch size
//flush and commit of inserts and release memory:
em.getTransaction().commit();
em.clear();
session.close();
【讨论】:
以上是关于使用 JPA/EJB3 进行批量插入的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 NamedParameterJdbcTemplate 进行批量插入
在 NpgSql 中使用 BeginBinaryImport 插入位数据类型进行批量数据插入
使用 Node.js/Sequelize 进行批量插入时 PostgreSQL 崩溃