3

ドメイン オブジェクトの大きなリストを処理する最善の方法は何ですか? たとえば、'Users' ドメインと 'Book' ドメインがあり、Book オブジェクトには READ 権限があります。新しいブックを追加するとき、このブックのすべてのユーザーに読み取り権限を設定したいと考えています。最初はコードでした:

def users = Users.findAll{ ... }
users.each { addPermission(book, it, READ) }  

Spring Security Core と ACL プラグインを使用しています。しかし今、10000 個のユーザー オブジェクトをメモリにロードするのは最善の方法ではないと思います。Criteria の maxResults(???) で SCROLL メソッドを使用します。だから私の質問は、何が最善の方法ですか? MaxResults の最適な数を決定する方法は?

4

3 に答える 3

2

このような場合は、一括更新を行います。ExecuteUpdate を使用すると、そのようなことを実行でき、パフォーマンスが大幅に向上します。この例を見て、必要に応じてカスタマイズしてください。

def updatedRecords = User.executeUpdate("update User set permission = 'READ' where somecriteriaOrNot ")
于 2013-09-17T11:44:08.560 に答える
1

これを行う Grails のより多くの方法は、バッチ処理を使用することです。以下の例を試してください: 編集: 改善された答え。現在、ページ付けベースのバッチ処理を使用しています。

             def noOfObjectsTobeProcessedAtAtime=1000//Step or pagination size...

    List offsetMaxMapList = (0..User.count()-1).step(noOfObjectsTobeProcessedAtAtime).collect{[max:noOfObjectsTobeProcessedAtAtime,offset:it]}
    offsetMaxMapList.each{offsetMaxMap->
        addPermissionToUserInBatch(params)  

    }

    def addPermissionToUserInBatch(params){
        def batch = []
                def session
                def users = Users.createCriteria().list(params){}

                users.eachWithIndex { user, index ->
                    batch << user

                    if (batch.size() >= batchSize) {
                        User.withTransaction {
                            batch.each {User userObject ->
                             addPermission(book, userObject, READ)
                                }
                        }
                        batch.clear()

                    } else if (batch.size() < batchSize && (users.size() - index - 1) == 0) {
                        User.withTransaction {
                            batch.each {User userObject ->
                                 addPermission(book, userObject, READ)
                                }
                        }
                        batch.clear()
                    }
                    session = sessionFactory.getCurrentSession()
                    session.clear()
                }

    }

それが役立つことを願っています!!!

于 2013-09-17T13:35:43.953 に答える
0

皆さん、ありがとうございました。まとめたいと思います。ti が私にとっての TEMPLATE になることを願っています。

def dc = new DetachedCriteria(Users).build{
    //some conditions of criteria 
}
def count = dc.count()

// Optional:            
// dc = dc.build{
//     projections { property('username') }
// }

def batchSize = 50 // Hibernate Doc recommends 10..50
0.step(count, batchSize){ offset-> 
    dc.list(offset:offset, max:batchSize).each{
       // doSmthWithTransaction(it)
    }
    //clear the first-level cache
    //def hiberSession = sessionFactory.getCurrentSession() 
    //hiberSession.clear()
    // or
    Users.withSession { session -> session.clear() }
}

PS doSmthWithTransaction メソッドで使用するため、ここではトランザクションを使用しません

于 2013-09-18T06:57:26.987 に答える