关于 spring/jpa/hibernate 乐观锁的简单设计问题

发布于 2024-10-19 19:19:22 字数 490 浏览 6 评论 0原文

我有一个 GeneralKnowledgeTest 对象,它包含许多统计字段( ratingsCount、responseCount、 ratingStars ...),每次用户进行该测试时都会更新这些统计字段(takeTest() -> 事务方法)。

可能会发生许多用户同时进行相同的测试,因此我正在考虑实现一个乐观锁定(@version)和一个拦截器,该拦截器会在抛出乐观锁定异常的情况下重试 takeTest 方法。

因此,在 takeTest 方法中,我总是获得一个新的 GeneralKnowledgeTest 实例,例如 entityManager.find(testId),然后更新其统计字段。如果抛出乐观异常,拦截器将简单地重试 takeTest 方法,直到成功为止。

您对此程序有何看法。对于可能有很多用户尝试进行相同测试的系统来说,这是实现乐观锁定的好方法吗?

附言。业务不会承认抛出乐观锁异常时会显示任何警告信息,所以拦截器是必须的才能顺利执行......

I have an object GeneralKnowledgeTest and it contains a lot of statistics fields (ratingsCount, responsesCount, ratingStars ...) which are updated every time a user will take that test (takeTest() -> transactional method).

It might happen that many users are taking the same test in the same time, so I was thinking about implementing an optimistic locking (@version) and a a interceptor which retries the takeTest method in case that the optimistic lock exception is thrown.

So, inside the takeTest method I always get a fresh GeneralKnowledgeTest instance, e.g. entityManager.find(testId), then update its statistics fields. In case that there is an optimistic exception thrown, the interceptor will simply retry the takeTest method until it will succeed.

What is your opinion about this procedure. Is this good way to implement optimistic locking for systems which may have lots of users trying to take same test?

PS. The business will not admit to display any warning messages in case that optimistic lock exception is thrown, so the interceptor is a must to allow smooth execution...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

你在看孤独的风景 2024-10-26 19:19:23

我假设这些统计数据仅在测试结束时更新,并且测试需要合理的时间来运行,因此这将减少乐观锁失败的可能性。另外,用户是否有可能突然完成测试,例如在设定的时间开始测试?这会增加锁失败的可能性。

如果吞吐量使得并发更新仍然可能发生,那么您最好将统计信息聚合在内存中(以线程安全的方式)并定期将它们写入数据库。

I assume these stats are only being updated at the end of the test and the tests take a reasonable amount of time to run, so this will reduced the likelihood of am optimistic lock failing. Also, is there any likelihood of users completing test in bursts, for instance, as a result of starting the test at a set time? This would increase the likelihood of the lock failing.

If the throughput is such that concurrent updates are still likely, then you would be better off aggregating the stats in memory (in a thread safe way) and periodically writing them to the the database.

家住魔仙堡 2024-10-26 19:19:23

这听起来是一个有效的方法:

Hibernate 在刷新时检查实例版本,如果检测到并发修改则抛出异常。由开发人员来捕获并处理此异常。常见选项是用户有机会合并更改或使用非过时数据重新启动业务对话。

您还可以查看将 IsolationLevel 设置为 SERIALIZED 或锁定表行。

另一种选择可能是分离对象,使用传入的统计信息更新它,然后使用调度程序等重新附加(更新)它。然而,这可能需要同步您的服务方法(更新统计信息),并且由于该服务可能是代理的,因此我认为不可能同步它。

This sounds like a valid approach:

Hibernate checks instance versions at flush time, throwing an exception if concurrent modification is detected. It is up to the developer to catch and handle this exception. Common options are the opportunity for the user to merge changes or to restart the business conversation with non-stale data.

You could also have a look at setting the IsolationLevel to SERIALIZED or locking the table row.

Another option might be detaching the object, updating it with stats coming in and reattach (update) it using a Scheduler or such. This however might require your service method (update stats) to be synchronized and since this service is probably proxied I don't think synchronizing it is possible.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文