5

私のアプリケーションはHibernate3.2とSpring2.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のこの解析メソッドは、データベースに多数の行(約5000)を格納する同じDAOの「save()」という別のメソッドを呼び出します。これで、saveメソッドがparse関数からループで呼び出されます。ここで問題となるのは、「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)を配置することにより、DAOでこの保存方法のトランザクション管理を個別に実行する必要があるかどうかわかりませんsave()。それともこのアプローチで問題ありませんか?

hibernate.jdbc.batch_sizeまた、hibernate.cfg構成ファイルのを20に更新しました。

助言がありますか?

4

3 に答える 3

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 は、現在のトランザクション コンテキストから独立しています。

于 2012-05-12T14:13:28.097 に答える
1

必要なのは、セッションをフラッシュしてクリアすることだけです。トランザクション管理はSpringにお任せください。sessionFactory.getCurrentSession()を使用して、Springがすでに開いているセッションに到達します。また、Springの最近の推奨事項は、HibernateTemplateを回避し、HibernateのAPIと直接連携することです。SessionFactoryをdao-beanに注入します。

于 2012-03-29T11:20:52.883 に答える
0

parse直接呼び出さない方法でリファクタリングしsaveますが、サービスレイヤーからコールバックを受け取ります。saveサービス層は、このコールバックとして call を使用してそのトランザクション メソッドを渡します。

あなたのケースで説明されているとおりに正確に機能しない場合がありますが、この短い説明から、これは私が試してみたいものです.

于 2012-03-15T11:17:50.647 に答える