Hibernate在grails中写出冲突

时间:2013-06-17 20:44:39

标签: hibernate grails

我正在使用Grails 1.3.7和MySQL。我的应用服务器记录用户运行的查询的搜索结果。模式(简化)由

组成
class Query {
    String query
    String user
}

class Document {
    String externalId
    String title
}

class Posting {
    Query query
    Document document
    int rank
}

每当用户运行第一次检索文档的查询时,我都会创建一个新实例;否则,我在创建相应的Posting实例时重用现有实例。对于给定的Document,只应存在externalId的一个实例,但多个Posting实例可以指向它。

多个用户可以运行检索相同文档的查询,但这会产生并发问题。如果两个用户几乎同时第一次检索到同一文档,则第二次创建Document的尝试将失败,并在externalId上发生唯一约束违规。这很好。不好的是,与重复Posting相关联的新创建的Document实例也将被回滚。这并不好,因为很难弄清楚如何重试保存。

我提出的解决方案是使用调用Document的synchronized方法创建save(flush: true),如果失败,则从数据库中重新读取文档。然后使用生成的文档(无论是保存还是重新读取)来填充Posting实例。此解决方案有效,但速度太慢,无法处理用户检索的结果。如果我删除了flush: true参数,性能会提高,但我无法保证DocumentPosting个实例会正确创建。

实施此类更新的正确方法是什么?

澄清

我正在运行的查询一次返回100个匹配项,这意味着我每个用户请求创建0-100个Document个实例和100个Posting个实例。

1 个答案:

答案 0 :(得分:1)

我可能不完全理解这个问题,所以这听起来有点天真。你能用optimistic locking来解决这个问题吗?

在你的catch区块中,假设第二个用户是迟到的那个用户,那么你不能拉出最新版本的文档并分配给第二个用户的帖子。

try {
    def posting = .... 
    posting.save(flush: true)
}
catch (org.springframework.dao.OptimisticLockingFailureException e) {
    def doc = Document.findByExternalId(posting.document.externalId)
    posting.document = doc
    posting.save(flush: true)
    ... 
}