5

GORM は、10.000 を超えるオブジェクトを含むバッチがない限り、そのままで問題なく動作します。最適化を行わないと、outOfMemory の問題に直面します。

一般的な解決策は、n (egn=500) 個のオブジェクトごとにセッションを flush() および clear() することです。

Session session = sessionFactory.currentSession
Transaction tx = session.beginTransaction();
def propertyInstanceMap = org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP

Date yesterday = new Date() - 1

Criteria c = session.createCriteria(Foo.class)
c.add(Restrictions.lt('lastUpdated',yesterday))
ScrollableResults rawObjects = c.scroll(ScrollMode.FORWARD_ONLY)

int count=0;
while ( rawObjects.next() ) {
    def rawOject = rawObjects.get(0);

    fooService.doSomething()

    int batchSize = 500
    if ( ++count % batchSize == 0 ) {
        //flush a batch of updates and release memory:
        try{
            session.flush();
        }catch(Exception e){
            log.error(session)
            log.error(" error: " + e.message)
            throw e
        }
        session.clear();
        propertyInstanceMap.get().clear()
    }
}

session.flush()
session.clear()
tx.commit()

しかし、解決できない問題がいくつかあります。

  1. currentSession を使用すると、セッションが空であるためコントローラーが失敗します
  2. sessionFactory.openSession() を使用すると、currentSession は FooService 内で引き続き使用されます。もちろん、session.save(object) 表記を使用できます。しかし、これは、fooService.doSomething() を変更し、単一操作 ( fooObject.save() のような一般的な grails 表記) とバッチ操作 (session.save(fooObject() .. 表記) のコードを複製する必要があることを意味します。
  3. Foo.withSession{session->} または Foo.withNewSession{session->} を使用すると、Foo クラスのオブジェクトは、期待どおりに session.clear() によってクリアされます。他のすべてのオブジェクトは clear() されないため、メモリ リークが発生します。
  4. もちろん、 evict(object) を使用して手動でセッションをクリアできます。しかし、関連付けの自動取得により、関連するすべてのオブジェクトを取得することはほぼ不可能です。

したがって、 FooService.doSomething() をより複雑にせずに問題を解決する方法がわかりません。すべてのドメインで withSession{} のようなものを探しています。または、開始時にセッションを保存し (Session tmp = currentSession)、sessionFactory.setCurrentSession(tmp) のようなことを行います。どちらも存在しません!

どんなアイデアでも大歓迎です!

4

2 に答える 2

1

この種のバッチ処理にはステートレス セッションを使用することをお勧めします。この投稿を参照してください:バッチ処理に StatelessSession を使用する

于 2015-09-30T10:02:08.130 に答える