Подтвердить что ты не робот

Массовая вставка ИЛИ обновление с гибернацией?

Мне нужно потреблять довольно большой объем данных из ежедневного файла CSV. CSV содержит около 120 тыс. Записей. Это замедляется при сканировании при использовании спящего режима. В принципе, кажется, что hibernate делает SELECT перед каждым INSERT (или UPDATE) при использовании saveOrUpdate(); для каждого экземпляра, сохраняемого с помощью saveOrUpdate(), SELECT выдается до фактического INSERT или UPDATE. Я могу понять, почему он это делает, но он ужасно неэффективен для выполнения массовой обработки, и я ищу альтернативы.

Я уверен, что проблема с производительностью связана с тем, как я использую спящий режим для этого, так как у меня есть другая версия, работающая с собственным SQL (который разбирает CSV в excat таким же образом) и его буквально запущенные круги вокруг этого новая версия)

Итак, к реальному вопросу, существует ли альтернатива спящего режима для mysqls? Синтаксис "INSERT... ON DUPLICATE"?

Или, если я захочу сделать собственный SQL для этого, могу ли я сделать собственный SQL в транзакции с гибернацией? Смысл, поддержит ли он фиксацию/откаты?

4b9b3361

Ответ 2

Существует множество возможных узких мест для массовых операций. Наилучший подход во многом зависит от того, как выглядят ваши данные. Просмотрите раздел Hibernate Manual для пакетной обработки.

Как минимум, убедитесь, что вы используете следующий шаблон (скопированный из руководства):

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

for ( int i=0; i<100000; i++ ) {
Customer customer = new Customer(.....);
session.save(customer);
    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
        //flush a batch of inserts and release memory:
        session.flush();
        session.clear();
    }
}

tx.commit();
session.close();

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

Наконец, если вам не нужно Hibernate обрабатывать любые коллекции или каскадировать для правильной установки ваших данных, рассмотрите возможность использования StatelessSession.

Ответ 3

От Пакетная обработка Hibernate Для обновления я использовал следующее:

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

ScrollableResults employeeCursor = session.createQuery("FROM EMPLOYEE")
                                   .scroll();
int count = 0;

while ( employeeCursor.next() ) {
   Employee employee = (Employee) employeeCursor.get(0);
   employee.updateEmployee();
   seession.update(employee); 
   if ( ++count % 50 == 0 ) {
      session.flush();
      session.clear();
   }
}
tx.commit();
session.close();

Но для вставки я бы пошел на jcwayne ответить

Ответ 4

Если вы используете последовательность или собственный генератор, Hibernate будет использовать select для получения id:

<id name="id" column="ID">
    <generator class="native" />
</id>

Вы должны использовать генератор hilo или seqHiLo:

<id name="id" type="long" column="id">  
    <generator class="seqhilo">
        <param name="sequence">SEQ_NAME</param>
        <param name="max_lo">100</param>
    </generator>
</id>

Ответ 5

"Дополнительный" выбор - это сгенерировать уникальный идентификатор ваших данных.

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