2012-03-15 2 views
5

Мое приложение основано на Hibernate 3.2 и Spring 2.5. Вот руководство сделки, связанное с сниппают контекста приложения:Пакетные вставки с гибернатом и весной

<tx:annotation-driven transaction-manager="txManager"/> 
    <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
      <property name="sessionFactory" ref="sessionFactory"/> 
      <property name="nestedTransactionAllowed" value="true"/> 
    </bean> 
    <bean id="transactionTemplate" classs="org.springframework.transaction.support.TransactionTemplate"> 
      <property name="transactionManager" ref="txManager"/> 
    </bean> 
    <bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/> 
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
    <property name="configLocation" value="classpath:/hibernate.cfg.xml"></property> 
    </bean> 

Для всех DAO там есть соответствующий класс обслуживания и операции обрабатываются там с помощью @Transactional каждого метода в слое обслуживания. Однако теперь существует сценарий, когда метод в DAO говорит, что «parse()» вызывается из служебного уровня. На сервисном уровне я указал @Transactional(readOnly=false). Этот метод анализа в DAO вызывает другой метод: «save()» в том же DAO, который хранит большое количество строк (около 5000) в базе данных. Теперь метод save вызывается в цикле из функции синтаксического анализа. Теперь проблема в том, что после примерно 100 вызовов метода «save». Иногда я получаю исключение OutOfMemory или иногда программа перестает отвечать на запросы.

Пока эти изменения, которые я сделал для метода сохранения:

Session session = getHibernateTemplate().getSessionFactory().openSession(); 
      Transaction tx = session.beginTransaction(); 

      int counter = 0; 
      if(books!=null && !books.isEmpty()){ 
       for (Iterator iterator = books.iterator(); iterator 
         .hasNext();) { 
        Book book = (Book) iterator.next(); 
        session.save(book); 
        counter++; 
        if(counter % 20==0) { 
         session.flush(); 
         session.clear(); 
        } 
       } 
      } 
      tx.commit(); 
     session.close(); 

Это единственный метод в моем приложении, где я начать транзакцию, как это и совершить его в конце метода. В противном случае я обычно звоню только getHibernateTemplate.save(). Я не уверен, должен ли я выполнять управление транзакциями для этого метода сохранения отдельно в DAO, разместив @Transactional(readOnly=false, PROPOGATION=NEW) по адресу save(), или этот подход в порядке?

Также я обновил hibernate.jdbc.batch_size до 20 в конфигурационном файле hibernate.cfg.

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

ответ

0

Я бы рефакторировал parse так, чтобы он не вызывал save напрямую, но требует некоторого обратного вызова из уровня обслуживания. Сервисный уровень передаст свой транзакционный метод с вызовом save как этот обратный вызов.

Он может не работать точно так, как описано в вашем случае, но из этого краткого описания это было бы чем-то, что я попробовал.

1

Вам нужен только бит с промывкой и очисткой сеанса. Оставьте управление транзакциями весной. Используйте sessionFactory.getCurrentSession() для доступа к сеансу, который Spring уже открыл для вас. Кроме того, недавняя рекомендация Spring заключается в том, чтобы избежать HibernateTemplate и работать напрямую с API Hibernate. Внесите SessionFactory в ваш dao-bean.

5

Для вставки пакетного с спячки, лучшая практика StatelessSession, она Безразлично `кэшировать любые состояния вашей организации, вы не встретите OutOfMemory, код, как:

if (books == null || books.isEmpty) { 
    return; 
} 
StatelessSession session = getHibernateTemplate().getSessionFactory().openStatelessSession(); 
Transaction tx = session.beginTransaction(); 

for (Book each : books) {   
    session.insert(book);   
} 
tx.commit(); 
session.close(); 

И сделка по StatelessSession не зависит от контекста текущей транзакции.

Смежные вопросы