Пакетные вставки с использованием JPA EntityManager
Есть ли способ, где мы можем использовать пакетные вставки с использованием JPA EntityManager. Я знаю, что не существует прямого пути для достижения этого, но должен быть какой-то способ для достижения этого механизма.
На самом деле, на каждую операцию вставки у меня уходит 300 мс, и я хочу уменьшить использование пакетных вставок вместо одиночных вставок.
Вот код, который я использую в настоящее время выполняется для одиночных вставок
@PersistenceContext(unitName = "testing")
EntityManager eM;
Query querys = this.eM.createNativeQuery(insertQuery);
for (String s : someList) {
//setting parameters
querys.executeUpdate();
}
Заранее спасибо.
4 ответа
Можно выполнять пакетную запись с использованием JPA, но это сильно зависит от конкретной реализации вашего поставщика сохраняемости, базы данных и драйвера JDBC. Например, в этой статье объясняется, как включить пакетную запись (оптимизация № 8) с использованием EclipseLink JPA 2.3 и базы данных Oracle. Найдите аналогичные параметры конфигурации в вашей конкретной среде.
Я знаю, что это довольно старый вопрос с принятым ответом. Тем не менее, я хотел бы дать новый ответ на эту очень специфическую тему "JPA batch inserts".
@PersistenceContext
private EntityManager entityManager;
@Value("${hibernate.jdbc.batch_size}")
private int batchSize;
public <T extends MyClass> Collection<T> bulkSave(Collection<T> entities) {
final List<T> savedEntities = new ArrayList<T>(entities.size());
int i = 0;
for (T t : entities) {
savedEntities.add(persistOrMerge(t));
i++;
if (i % batchSize == 0) {
// Flush a batch of inserts and release memory.
entityManager.flush();
entityManager.clear();
}
}
return savedEntities;
}
private <T extends MyClass> T persistOrMerge(T t) {
if (t.getId() == null) {
entityManager.persist(t);
return t;
} else {
return entityManager.merge(t);
}
}
Источник: http://frightanic.com/software-development/jpa-batch-inserts/
В зависимости от того, включает ли транзакция цикл, пакетирование обычно происходит в вашем случае.
JPA соберет все ваши обновления в своем кеше L1 и, как правило, записывает все это в БД в пакете при фиксации транзакции. На самом деле это не сильно отличается от пакетной обработки в JDBC, где каждый добавляемый пакетный элемент также временно находится в памяти до тех пор, пока вы не вызовете метод обновления.
Потенциально проблематично то, что у вас нет твердых гарантий того, что JPA действительно делает это пакетирование вообще, и делает ли это при фиксации транзакции или когда достигается порог, но я обнаружил, что на практике почти во всех случаях, особенно в случаях, связанных с таким простой цикл обновления, он действительно выполняет пакетную обработку.
Одна из проблем заключается в том, что даже если JPA действительно уже выполняет пакетную обработку, вы все равно можете контролировать размеры пакетов. Статьи, связанные другими ответами, предоставляют довольно полезную информацию для этого.
Наконец, вы должны знать, что ваш кэш L1 продолжает расти в цикле, поэтому, если количество обновлений действительно велико, периодически очищайте его. В качестве альтернативы, если ваша бизнес-логика может выдержать это, выполните частичные обновления в нескольких транзакциях. Например, от 0 до 100.000 в транзакции 1, от 100.001 до 200.000 в транзакции 2 и т. Д.
JPA сама по себе не имеет никаких настроек для дозирования. Однако есть некоторые зависящие от реализации настройки. Вот пример для спящего режима.