批量插入Hibernate&弹簧 [英] Batch Insertions with Hibernate & Spring

查看:132
本文介绍了批量插入Hibernate&弹簧的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序基于Hibernate 3.2和Spring 2.5。以下是来自应用程序上下文的事务管理相关代码片段:

 < tx:注解驱动的事务管理器=txManager /> 
< bean id =txManagerclass =org.springframework.orm.hibernate3.HibernateTransactionManager>
< property name =sessionFactoryref =sessionFactory/>
< property name =nestedTransactionAllowedvalue =true/>
< / bean>
< bean id =transactionTemplateclasss =org.springframework.transaction.support.TransactionTemplate>
< property name =transactionManagerref =txManager/>
< / bean>
< bean class =org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor/>
< bean id =sessionFactoryclass =org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean>
< property name =configLocationvalue =classpath:/hibernate.cfg.xml>< / property>
< / bean>

对于所有的DAO,都有相关的Service类,事务在那里使用 @Transactional 在服务层中的每个方法上。然而,现在有一种情况是DAO中的一个方法从服务层调用parse()。在服务层中,我指定了 @Transactional(readOnly = false)。 DAO中的这种解析方法在存储大量行(大约5000)到数据库中的同一DAO中调用另一种方法save()。现在,从解析函数的循环中调用save方法。现在的问题是,在大约100次调用save方法后,我有时会得到一个OutOfMemory异常或者有时程序停止响应。



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

pre $ 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),我不确定是否应该在DAO中单独执行此保存方法的事务管理> save(),或者这种方法还行吗?

我也更新了 hibernate.jdbc.batch_size 到20在hibernate.cfg配置文件中。



有什么建议?

解决方案

对于使用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的交易与当前的交易上下文无关。


My application is based on Hibernate 3.2 and Spring 2.5. Here is the transaction management related snippet from the application context:

  <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>

For all the DAO's there are relevant Service class and the transactions are handled there using @Transactional on each method in the service layer. However there is a scenario now that a method in DAO say "parse()" is called from the service layer. In the service layer I specified @Transactional(readOnly=false). This parse method in the DAO calls another method say "save()" in the same DAO which stores a large number of rows (around 5000) in the database. Now the save method is called in a loop from the parse function. Now the issue is that after around 100 calls to the "save" method.. i sometimes get a OutOfMemory Exception or sometimes the program stops responding.

For now these are the changes which I have made to the save method:

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();

This is the only method in my application where I start a transaction like this and commit it at the end of method. Otherwise I normally just call getHibernateTemplate.save(). I am not sure whether I should perform transaction management for this save method separately in the DAO by placing @Transactional(readOnly=false, PROPOGATION=NEW) on save(), or is this approach okay?

Also I have updated the hibernate.jdbc.batch_size to 20 in the hibernate.cfg configuration file.

Any suggestions?

解决方案

For the batch insertion with hibernate, the best practice is StatelessSession, it doesn`t cache any states of your entity, you will not encounter OutOfMemory, the code like:

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();

And the Transaction of StatelessSession is independent from the current transaction context.

这篇关于批量插入Hibernate&amp;弹簧的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆