处理Grails中的并发修改(GORM),同时避免过时的对象异常

时间:2013-08-13 13:04:00

标签: hibernate grails gorm

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

背景


My Grails应用程序用作REST API,并且具有数据的加密方法,该方法依赖于计数器变量作为密码的腌制机制。

此计数器变量必须才能维护,并且不能低,因为数据会发送到发卡后 不能修改的SIM卡,因此它重要的是我正确地维护这个计数器。此外,如果计数器不正确,SIM将拒绝该消息。

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

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

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

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

  • 关闭乐观锁定(这似乎是糟糕想法
  • 启用动态更新(我不认为这会对我有所帮助,因为我仍在同时更新同一行
  • lock对象 - 但我认为由于对象在第二次被访问时被锁定,它仍会引发异常?
  • 使用我认为与开启动态更新类似的executeUpdate?在我的用例中可能没用。

问题


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

最终,我的最终目标是拒绝任何请求,因此如果上面的事务机制存在(我认为这将是某种悲观锁定)并且所述事务机制拒绝该请求作为对象被锁定,我宁愿其他一些解决方案,因为我想不惜一切代价避免拒绝对服务的请求,因为它使先前交付给客户端变得复杂。

我想到的当前解决方案只是:

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

但是......非常难看。

1 个答案:

答案 0 :(得分:0)

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

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