2012-03-15 123 views
5

我的應用程序基於Hibernate 3.2和Spring 2.5。下面是從應用程序上下文相關的片段中,交易管理:使用Hibernate和Spring批量插入

<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中的這種解析方法在存儲大量行(大約5000)到數據庫中的同一DAO中調用另一種方法「save()」。現在,從解析函數的循環中調用save方法。現在的問題是,大約100次調用「保存」方法後..我有時得到一個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()。我不確定我是否應該通過將@Transactional(readOnly=false, PROPOGATION=NEW)放置在save()上單獨在DAO中對此保存方法執行事務管理,或者這種方法是否可行?

此外,我已經在hibernate.cfg配置文件中將hibernate.jdbc.batch_size更新爲20。

有什麼建議嗎?

回答

0

我會以直接不呼叫save的方式重構parse,但需要從服務層進行一些回調。服務層將通過其調用save調用的交易方法作爲此回調。

它可能無法完全按照你的情況描述,但從這個簡短的描述,這將是我想嘗試的東西。

1

您只需要刷新該位並清除會話。將交易管理留給Spring。使用sessionFactory.getCurrentSession()來訪問Spring已經爲你打開的會話。此外,Spring最近的推薦是避免使用HibernateTemplate,並直接使用Hibernate的API。將SessionFactory注入您的dao-bean。

5

對於批量插入與Hibernate,最好的做法是StatelessSession,它不`噸緩存你的實體的任何國家,你不會遇到內存不足時,這樣的代碼:

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的交易獨立於當前的事務上下文。