java - 使用 Hibernate 和 Spring 批量插入

标签 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,都有相关的服务类,并且在服务层的每个方法上使用 @Transactional 处理事务。但是现在有一种情况,DAO 中的一个方法说“parse()”是从服务层调用的。在服务层我指定了@Transactional(readOnly=false)。 DAO 中的这个解析方法调用同一个 DAO 中的另一个方法“save()”,它在数据库中存储大量行(大约 5000 行)。现在 save 方法在 parse 函数的循环中被调用。现在的问题是,在调用“保存”方法大约 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。

有什么建议吗?

最佳答案

对于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是独立于当前事务上下文的。

关于java - 使用 Hibernate 和 Spring 批量插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9718305/

相关文章:

java - HttpClient 已弃用(android studio,Target=api 22)

java - JAX-WS WSDL 看起来很奇怪

spring - 如何在Spring Boot中的存储库中的@Aggregation注释中添加 "allowDiskUse"?

hibernate - 当只需要实体 id 时如何避免初始化 Hibernate 代理

java - 将一个枚举复制到另一个java

java - Minecraft Forge Mod 命令不起作用?

java - 2 个 POST 请求处理程序(ResponseBody + "Normal")

java - java中的智能POJO转换

java - 如何使用 hibernate 保存新创建的父实体和子实体?

java - Java 中的 JAXB 字符串到 JPA 日期