1

我将 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实例可以指向它。

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

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

实施这种更新的正确方法是什么?

澄清

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

4

1 回答 1

1

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

在您的 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)
    ... 
}
于 2013-06-17T21:04:37.450 回答