批量插入与Hibernate&弹簧

时间:2012-03-15 10:57:39

标签: java spring hibernate spring-batch insertion

我的应用程序基于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,都有相关的Service类,并且使用@Transactional对服务层中的每个方法处理事务。但是现在有一个场景,DAO中的方法说服务层调用“parse()”。在服务层中,我指定了@Transactional(readOnly=false)。 DAO中的这个解析方法在同一个DAO中调用另一个方法说“save()”,它在数据库中存储了大量的行(大约5000个)。现在,在解析函数的循环中调用save方法。现在的问题是,在大约100次调用“保存”方法之后..我有时会得到OutOfMemory异常或有时程序停止响应。

现在这些是我对save方法所做的更改:

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.

有什么建议吗?

3 个答案:

答案 0 :(得分:5)

对于使用hibernate的批量插入,最好的做法是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的Transaction与当前的事务上下文无关。

答案 1 :(得分:1)

您只需要刷新并清除会话。将事务管理留给Spring。使用sessionFactory.getCurrentSession()来访问Spring已经为您打开的会话。另外,Spring最近推荐的是避免使用HibernateTemplate并直接使用Hibernate的API。将SessionFactory注入你的dao-bean。

答案 2 :(得分:0)

我会以不直接调用parse但从服务层进行回调的方式重构save。服务层将通过save调用传递其事务方法作为此回调。

它可能无法完全按照您的情况所述,但从这个简短的描述中我会尝试这样做。