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

krs*_*ynx 6 grails hibernate grails-orm

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

背景


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

这个计数器变量必须保持,并且不能低,因为数据将发送到发卡后不能修改计数器的SIM卡,因此正确维护此计数器非常重要.此外,如果计数器不正确,SIM将拒绝该消息.

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

  • getcontroller带标识符的对象1
  • 修改counter对象的成员/行
  • save 物体

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

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

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


我想知道是否有一些我可以使用的交易机制?即一个方法来检查某个对象当前处于锁定状态,如果是这样,睡眠对于t允许交易在数据库中完成.

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

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

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

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

and*_*and 0

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

def controller = Controller.lock(params.id)
controller.counter += 1
controller.save()
Run Code Online (Sandbox Code Playgroud)