Портативная JPA Batch / Bulk Insert - PullRequest
       8

Портативная JPA Batch / Bulk Insert

4 голосов
/ 01 сентября 2009

Я только что наткнулся на функцию, написанную кем-то другим, которая кажется немного неэффективной, но мои знания JPA не так уж хороши, чтобы найти портативное решение, не относящееся к Hibernate.

В двух словах, метод Дао, вызываемый в цикле для вставки каждой из новых сущностей, выполняет "entityManager.merge (object);".

Не существует ли способ, определенный в спецификациях JPA, для передачи списка сущностей в метод Dao и выполнения массовой / пакетной вставки вместо вызова слияния для каждого отдельного объекта?

Плюс, так как метод Dao аннотирован с / "@Transactional", мне интересно, происходит ли каждый отдельный вызов слияния в пределах его собственной транзакции ... который не снизит производительность.

Есть идеи?

Ответы [ 2 ]

7 голосов
/ 01 сентября 2009

Нет, в 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.

0 голосов
/ 26 июня 2012

Что бы вы могли сделать, если бы у вас было лукавое настроение, это:

@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

Из-за каскада объекты будут вставлены в одну операцию.

Я сомневаюсь, что в этом есть какое-то практическое преимущество перед простым сохранением отдельных объектов в цикле. Было бы интересно взглянуть на SQL, выданный реализацией JPA, и сравнить его с результатами.

...