2012-03-15 82 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的交易独立于当前的事务上下文。