Гибернация и пакетное обновление - PullRequest
2 голосов
/ 11 октября 2011

Хотя я вижу много дискуссий о Hibernate и Batch Update, вот мой конкретный сценарий, я надеюсь получить комментарии от всех экспертов.Я перебираю список объектов Document и для каждого документа мне нужно обновить таблицу DOCUMENT_METADATA свойством из объекта Document.

Я могу просто использовать стандартное пакетное обновление JDBC 2.0 для этого.Тем не менее, использование JDBC будет противоречить стандарту программного обеспечения в моем месте для использования Hibernate во всем приложении, и я не хочу делать исключение.

Чтобы использовать Hibernate, я должен сначала получить объект DocumentMetadata, учитывая документИдентификатор объекта Document, который я перебираю, задайте свойство DocumentMetadata и затем обновите таблицу.

Я могу сделать что-то вроде

    for each document { 
    //fetch DocumentMetadata object given the id from Document 
    //invoke setter on DocumentMetadata object  
    em.persist(DocumentMetadata);
    if (count % 50 == 0) { 
    em.flush(); //flush a batch of updates and release memory:
    em.clear();
    }

}

Для n записей (я буду запускать около 10 000 записей ввремя), как в лучшем случае я не делаю n выбирает = 1 обновление с подходом Hibernate выше?Учитывая размер моей таблицы (таблица DOCUMENT_METADATA содержит более 100 столбцов и 1 миллион записей), я боюсь, что столкнусь с проблемой производительности, сопоставленной с подходом JDBC.

Любые предложения?

Спасибо, KOB

Ответы [ 3 ]

3 голосов
/ 11 октября 2011

JPA, hibernate абсолютно поддерживает пакетные операции. Делайте то, что вы делаете с jdbc, но делайте это с this .

2 голосов
/ 23 мая 2013

Это мой код для пакетного сохранения / обновления.Я делаю это таким образом, потому что у нас есть предел партии в 1000 записей для вставки.Если в коллекции 25 тыс. Записей, она будет вставлена ​​партиями по 1000 штук.

private static int BATCH_SIZE = 1000; // current batch limit 

private void saveBulkEntries(
        final Collection<? extends MyObject> entries,
        final String insertSql) {
    if (entries.isEmpty()) {
        return;
    }

    // Create a new session independent of the current hibernate session
    // This avoids problems with the job transactions
    StatelessSession session = this.hibernateTemplate.getSessionFactory()
            .openStatelessSession();

    Transaction transaction = null;

    Long entryCounter = 0L;

    PreparedStatement batchUpdate = null;
    try {
        transaction = session.beginTransaction();
        batchUpdate = session.connection().prepareStatement(insertSql);

        for (MyObject entry : entries) {
            entry.addEntry(batchUpdate);
            batchUpdate.addBatch();

            if (++entryCounter % BATCH_SIZE == 0) {
                // Reached limit for uncommitted entries, so commit
                batchUpdate.executeBatch();
            }
        }

        // Commit any entries that have not been committed yet
        batchUpdate.executeBatch();
        batchUpdate.close();
        batchUpdate = null;
    }
    catch (HibernateException ex) {
        transaction.rollback();
        transaction = null;
    }
    catch (SQLException ex) {
        transaction.rollback();
        transaction = null;
    }
    finally {
        if (transaction != null) {
            transaction.commit();
        }

        if (batchUpdate != null) {
            try {
                batchUpdate.cancel();
                batchUpdate.close();
            }
            catch (SQLException ex) {

            }
        }

        session.close();
    }
}
2 голосов
/ 11 октября 2011

В дополнение к отличному совету от hvgotcodes (который указывает на документ гибернации о том, как использовать пакетные обновления и как обрабатывать тысячи объектов в одной транзакции без проблем с памятью), вы можете использовать оптимизацию для получения DocumentMetaData кусками, а не по одному.

Размер чанка также должен совпадать с размером пакета JDBC. И вам просто нужно разделить ваши N идентификаторов документов на куски (например) 20 и использовать предложение where id in (:idsOfChunk).

Наконец, я хотел бы отметить, что призыв к постоянству бесполезен: сущность, которая была загружена из базы данных с помощью диспетчера сущностей, присоединяется, и любое изменение, внесенное в эту сущность, автоматически записывается в базу данных при сбросе. время.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...