Является ли пакетное обновление Hibernate

Итак, это мой первый вопрос, так что вот оно... Идея в том, что я делаю большое количество операторов обновления для таблицы базы данных. В sql это было бы просто update table_name set col1 = 123 where col2 = 456 and col1 is null, Так как их миллионы, лучше всего сгруппировать их вместе. Я следовал указаниям здесь:
http://docs.jboss.org/hibernate/orm/3.3/reference/en-US/html/batch.html
и несколько других страниц, которые я случайно нашел здесь на stackru и других местах, но все они читаются одинаково. Моя идея состояла в том, чтобы не читать, а просто обновлять и продолжать цикл следующим образом:

  sessionFactory = new Configuration().configure("finaldetail/hibernate.dev.cfg.xml") 
          .addPackage("com.xxx.app.ftm.domain.event").addAnnotatedClass(FinalTrainDetail.class) 
          .addAnnotatedClass(AbstractDetail.class).addAnnotatedClassFinalTrainDetailWork.class).buildSessionFactory();
      inputStream = new BufferedReader(new FileReader(new File(args[0])));
      session = sessionFactory.openSession();
      transaction = session.beginTransaction(); 
      String s; 
      int count = 0; 
      while ((s = inputStream.readLine()) != null) {
        Query query = session.createQuery("update FinalTrainDetail  detail set detail.trainSummary "
                + "=:summaryId where detail.trainDetail=:detailId and detail.trainSummary=null"); 
        query.setParameter("summaryId", new Long(s.substring(9, 18)));
        query.setParameter("detailId", new Long(s.substring(0, 9)));
        query.executeUpdate();
        count++; 
        if (count % 20 == 0) { 
          log.debug("should commit"); 
          session.flush(); 
          session.clear(); 
        } 
      } 
      transaction.commit();
      System.out.println("exit");
    } catch (IOException e) {
      transaction.rollback();
      log.error(e.toString());
    } catch (Throwable t) {
      System.out.print(t);
      log.error("exception caught during Updateing Offline", t);
      System.exit(2);
    } finally {
      if (inputStream != null)
        inputStream.close();
      session.close();
    }

Таким образом, понимание здесь заключается в том, что сброс приведет к фиксации каждые 20 обновлений, а затем очистит кэш первого уровня, чтобы избежать исключения OutOfMemory.

Пока конфиг у меня есть

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
  <session-factory>
    <!-- SQL dialect -->
    <property name="dialect">org.hibernate.dialect.Oracle10gDialect</property> 

    <!-- Database connection settings --> 
    <property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property> 
    <property name="connection.url">jdbc:oracle:thin:@dev264.oracle.XXXX.com:1521:DEV264</property>
    <property name="connection.username">XXXX</property>
    <property name="connection.password">XXX</property>
    <property name="connection.shutdown">true</property>

    <!-- JDBC connection pool (use the built-in one) -->
    <property name="connection.pool_size">1</property> 

    <!-- Enable Hibernate's automatic session context management -->
    <property name="current_session_context_class">thread</property>

    <!-- Disable the second-level cache  --> 
    <property
     name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

    <!-- disable batching so HSQLDB will propagate errors correctly. -->
    <property name="jdbc.batch_size">20</property> 

    <!-- Echo all executed SQL to stdout -->
    <property name="show_sql">true</property> 

  </session-factory>
</hibernate-configuration>

Show sql включен в целях отладки. Так что я не получаю или не вижу, когда я устанавливаю в log4j

<logger name="org.hibernate.transaction">
    <level value="debug"/>
    <appender-ref ref="file"/>
    <appender-ref ref="console"/>
</logger>

Я вижу только

[DEBUG] [main] [org.hibernate.transaction.JDBCTransaction] [commit] 
[DEBUG] [main] [org.hibernate.transaction.JDBCTransaction] [commit] 
[DEBUG] [main] [org.hibernate.transaction.JDBCTransaction] [commit] 

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

2 ответа

Ты путаешь flush() а также commit(), flush() не совершает транзакцию. Все, что он делает - выполняет операторы update и delete для записи в базу данных изменений, которые были применены в памяти, к присоединенным объектам, и которые еще не были сделаны постоянными.

В вашем случае очистка и очистка сеанса бесполезны (но безвредны), так как вы не применяете никаких изменений в памяти, и, таким образом, сеанс всегда пуст.

AFAIK, создание нового запроса на каждой итерации также бесполезно. Вы можете использовать один и тот же запрос снова и снова. А также detail.trainSummary=null это неверно. Так должно быть detail.trainSummary is null,

Я бы прокомментировал ваш ответ выше, но количество слов слишком велико...
Хорошо, так что, по крайней мере, вы не отправили мне ссылку на этот вопрос, который мне задавали ранее, так что я чувствую себя немного лучше, но я думаю, что понимаю вашу точку зрения
Таким образом, эта версия приложения была похожа на 3-ю версию, и скоро будет 4-я версия. Мы не будем повторять запрос. Моя оригинальная версия произвела чтение (в память), затем вызвала сеттер (изменение объекта в памяти). Где-то у меня появилась идея, пропустить выбор и просто обновить. Таким образом, если a сделал чтение, то изменил состояние, очистка и очистка стали бы необходимыми. Поскольку не было чтения, нечего очищать или очищать. Так что я никак не могу исчерпать память в кеше первого уровня. Моя настоящая проблема была в том, чтобы Oracle использовал слишком много памяти программной глобальной области (PGA) и занимал слишком много места для отмены. Я читал об этом здесь:
http://www.oracle.com/technetwork/issue-archive/2008/08-mar/o28plsql-095155.html
Поэтому каждые 20–100 обновлений не вызывайте flush в сеансе, а фиксируйте транзакцию. Кроме того, я должен отслеживать количество строк, изменяемых из вызова executeUpdate, а не просто считать каждый раз, когда выполняется запрос. Итак, я получаю что-то вроде этого:

Query query = session.createQuery("update FinalTrainDetail  detail set detail.trainSummary "
      + "=:summaryId where detail.trainDetail=:detailId and detail.trainSummary=null");
  while ((s = inputStream.readLine()) != null) {
    transaction = session.beginTransaction();
    query.setParameter("summaryId", new Long(s.substring(9, 18)));
    query.setParameter("detailId", new Long(s.substring(0, 9)));
    count+=query.executeUpdate();
    if (count % 100 == 0) {
      log.debug("should commit");
      transaction.commit();
    }
  }
  transaction.commit();
  System.out.println("exit");

Другие вопросы по тегам