我在 Grails 中遇到了一个问题,我认为这可能是如何处理并发的潜在问题;而且我不确定如何最好地处理这个问题(或者如果已经有解决方案/实践我可以适应)。
背景
我的 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
允许事务在数据库中完成。
最终,我的最终目标是不拒绝任何请求,因此如果上面的事务机制存在(我假设这将是某种悲观锁)并且所述事务机制在对象被锁定时拒绝请求,我宁愿其他一些解决方案因为我想不惜一切代价避免拒绝对服务的请求,因为这会使之前向客户的交付变得复杂。
我正在考虑的当前解决方案是:
try {
Foo.save()
catch (RespectiveException ex) {
Thread.sleep(1000)
if(depth < 3) {
recursiveCallToThisMethod(depth++)
} else {
render(letTheUserKnowWhyItFailed)
}
}
但是,是的......非常丑陋。