我在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)
}
}
但是......非常难看。
答案 0 :(得分:0)
尝试悲观锁定。第二个请求不会有异常,它会阻塞直到第一个请求完成。
def controller = Controller.lock(params.id)
controller.counter += 1
controller.save()