【问题标题】:Handling Concurrent Modifications in Grails (GORM) while avoiding Stale Object Exceptions在 Grails (GORM) 中处理并发修改,同时避免过时对象异常
【发布时间】:2013-08-15 02:47:57
【问题描述】:

我在 Grails 中遇到了一个问题,我认为这可能是并发处理方式的潜在问题;而且我不确定如何最好地处理这个问题(或者如果已经有解决方案/实践我可以适应)。

背景


我的 Grails 应用程序用作 REST API,并且有一种数据加密方法,该方法依赖于 counter 变量作为密码的加盐机制。

这个计数器变量必须被维护,并且不能更低,因为数据将进入 SIM 卡,其中计数器不能在发行后修改,因此它我正确维护这个计数器很重要。此外,如果计数器不正确,SIM 卡也会拒绝该消息。

当用户调用时,例如:http://example.tld/service/controller/action?id=1,服务器将执行以下操作:

  • get 具有标识符 1 的对象 controller
  • 修改对象的counter成员/行
  • save对象

对于超过 20,000 个请求,这很好。但是,有两次,我有一个StaleObjectException,由于对象在同一时间被访问,我已经确定会发生这种情况。我已经确定这种情况正在发生,因为我提供的包装 API 使用了 10 个线程,并且偶然两个线程同时调用了 action

我已阅读并注意到我可以:

  • 关闭乐观锁定(这似乎是一个主意
  • 打开动态更新(我认为这对我没有帮助,因为我仍在同时更新同一行
  • lock 对象——但我认为这仍然会引发异常,因为对象在第二次被访问时被锁定?
  • 使用executeUpdate,我认为这类似于打开动态更新?在我的用例中可能没用。

问题


我想知道是否有一些我可以使用的交易机制? IE。检查对象当前是否被锁定的方法,如果是,sleep for t 以允许事务在数据库中完成。

最终,我的最终目标是拒绝任何请求,因此如果上面的事务机制存在(我假设这将是某种悲观锁)并且所述事务机制拒绝请求,因为对象被锁定,我宁愿采用其他解决方案,因为我想不惜一切代价避免拒绝对服务的请求,因为这会使之前向客户的交付复杂化。

我正在考虑的当前解决方案是:

try { 
    Foo.save()
catch (RespectiveException ex) {
    Thread.sleep(1000)
    if(depth < 3) {
        recursiveCallToThisMethod(depth++)
    } else {
        render(letTheUserKnowWhyItFailed)
    }
}

但是是的……很丑。

【问题讨论】:

  • 通常情况下,客户端会处理并发修改异常,然后必须重试操作。
  • 这个问题可能会有所帮助:stackoverflow.com/questions/129329/…
  • 你有没有想出任何解决方案?我也有同样的问题。我唯一能想到的尝试是有一个同步块锁对象的并发哈希映射,由域对象本身的唯一键引用并由服务单例持有。当调用服务方法时,它首先检查映射以查看域对象键值是否已经存在锁定对象,并在同步块中使用它。如果锁定对象不存在,它会创建一个并将其存储到地图中。完成后,必须在 finally 块中从地图中删除对象
  • StaleObjectException 发生在对象被数据库锁定时,因此您需要考虑发生这种情况的原因。如果您要存储新数据,则需要进行一些验证,但是如果您只是定期更新,那么您可以等到锁返回并重新尝试操作(但是在高流量系统中,这可能会导致发送到服务器的“最新”内容与数据库中的内容的错误陈述)。我认为,尝试理解为什么必须如此频繁地更新成员可能会更好。或许添加临时数据是一种方法。
  • 尝试使用 object.refresh 和 object.merge。 refresh 将避免 staleobjectexception 和 merge 将允许在 hibenrate 中合并两个具有不同状态的对象。

标签: hibernate grails grails-orm


【解决方案1】:

尝试悲观锁定。第二个请求不会有异常,它只会阻塞直到第一个请求完成。

def controller = Controller.lock(params.id)
controller.counter += 1
controller.save()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多