便携式JPA批/大容量插入

时间:2009-09-01 15:06:17

标签: jpa insert bulk

我刚刚跳过了其他人写的功能,这个功能看起来效率不高,但是我对JPA的了解并不是很好找到一个不是特定于Hibernate的可移植解决方案。

简而言之,在一个循环中调用的Dao方法插入每个新实体都会执行“entityManager.merge(object);”。

是不是在JPA规范中定义了一种方法来将实体列表传递给Dao方法并执行批量/批量插入而不是为每个对象调用merge?

另外,由于Dao方法带有“@Transactional”注释,我想知道每个合并调用是否在自己的事务中发生......这对性能没有帮助。

有什么想法吗?

2 个答案:

答案 0 :(得分:7)

在vanilla JPA中没有批量插入操作。

是的,每个插入都将在自己的事务中完成。 @Transactional属性(没有限定符)表示传播级别为REQUIRED(如果事务尚不存在,则创建一个事务)。假设你有:

public class Dao {
  @Transactional
  public void insert(SomeEntity entity) {
    ...
  }
}

你这样做:

public class Batch {
  private Dao dao;

  @Transactional
  public void insert(List<SomeEntity> entities) {
    for (SomeEntity entity : entities) {
      dao.insert(entity);
    }
  }

  public void setDao(Dao dao) {
    this.dao = dao;
  }
}

这样,整个插入组就会被包装在一个事务中。如果您正在谈论大量插入,您可能希望将其拆分为1000,10000或其他任何组合,因为足够大的未提交事务可能会使数据库资源匮乏,并且可能由于大小而单独失败。

注意: @Transactional是一个Spring注释。请参阅Spring Reference中的Transactional Management

答案 1 :(得分:0)

如果你有一种狡猾的心情,你可以做的是:

@Entity
public class SomeEntityBatch {

    @Id
    @GeneratedValue
    private int batchID;
    @OneToMany(cascade = {PERSIST, MERGE})
    private List<SomeEntity> entities;

    public SomeEntityBatch(List<SomeEntity> entities) {
        this.entities = entities;
    }

}

List<SomeEntity> entitiesToPersist;
em.persist(new SomeEntityBatch(entitiesToPersist));
// remove the SomeEntityBatch object later

由于级联,这将导致实体插入一次操作。

我怀疑在简单地将单个对象保持在循环中这样做有任何实际优势。查看JPA实现发出的SQL以及基准测试将会很有趣。