Jakarta ee Jpa对计数器变量的并发访问

Jakarta ee Jpa对计数器变量的并发访问,jakarta-ee,jpa,concurrency,jpa-2.0,java-ee-7,Jakarta Ee,Jpa,Concurrency,Jpa 2.0,Java Ee 7,我的用例尽可能简单:我想给多个用户一个计数器增加1的可能性。现在,使用乐观并发策略,两个用户可能同时尝试更新计数器,并引发OptimisticLockException。如果我理解正确,如果我没有显式调用EntityManager#flush,OptimisticLockException将被包装到系统异常中。现在,当这种情况发生时,事务将回滚。但是我如何才能完成事务重试直到最终成功?因为我只想将计数器增加1,所以我不需要合并两个更新。我只想绝对确保没有增量丢失,我也不想回到用户那里,让他再次执

我的用例尽可能简单:我想给多个用户一个计数器增加1的可能性。现在,使用乐观并发策略,两个用户可能同时尝试更新计数器,并引发OptimisticLockException。如果我理解正确,如果我没有显式调用EntityManager#flush,OptimisticLockException将被包装到系统异常中。现在,当这种情况发生时,事务将回滚。但是我如何才能完成事务重试直到最终成功?因为我只想将计数器增加1,所以我不需要合并两个更新。我只想绝对确保没有增量丢失,我也不想回到用户那里,让他再次执行增量。

我假设您的用例只是并发访问或某种测试或展示的示例,对吗

如果没有,您可以让数据库来执行,或者按照建议使用序列,或者将其封装在您自己的数据库脚本中,任意客户端都可以使用该脚本

如果是这样的话,那么不管它是一个计数器还是由查询或持久化实体执行的任何其他操作,问题总是一样的:至少有两个不同的请求试图触发相同的更新,其中一个将失败


因此,您可以做的是专门针对您的用例处理问题,并决定(例如)重新加载已更改的实体并从那里开始,或者实现一种通用重试机制,该机制将对同一语句/用例重试一定的时间/次数(你不应该不这样做,因为这会严重损害你的应用程序)。如果要使用现有的实现,请尝试在google上搜索
RetryProxy

,捕获异常并重新启动事务,直到成功。我不是100%确定,但使用类似
update…set counter=counter+1
的查询应该可以防止任何丢失风险,特别是如果将隔离级别设置为可序列化。如果您的数据库支持序列,您也可以使用它。那么您是说使用jpql更新查询对于这个用例来说应该足够安全?它是否比获取实体、增加值然后再次持久化更新的实体更安全?它显然更快、更原子,因为增量是由da完成的tabase本身。因此并发更新的可能性较低。我不能为您提供字符串保证,但我的常识告诉我,它是原子的,至少在隔离级别可序列化的情况下。请查看数据库的文档。