我有一个对象GeneralKnowledgeTest,它包含许多统计字段(ratingsCount,respondCount,ratingStars ......),每次用户进行该测试时都会更新(takeTest() - >事务方法)。
许多用户可能会同时进行相同的测试,因此我考虑实现乐观锁定(@version)和拦截器,以便在抛出乐观锁定异常的情况下重试takeTest方法。
因此,在takeTest方法中,我总是得到一个新的GeneralKnowledgeTest实例,例如 entityManager.find(testId),然后更新其统计字段。如果抛出了一个乐观异常,拦截器将只是重试takeTest方法,直到它成功。
您对此程序有何看法?对于可能有很多用户尝试进行相同测试的系统,这是实现乐观锁定的好方法吗?
PS。如果抛出乐观锁异常,业务将不承认显示任何警告消息,因此拦截器是必须允许顺利执行...
答案 0 :(得分:0)
我认为这些统计数据仅在测试结束时更新,并且测试需要花费合理的时间来运行,因此这将降低乐观锁定失败的可能性。此外,用户是否有可能在突发事件中完成测试,例如,由于在设定的时间开始测试?这会增加锁定失败的可能性。
如果吞吐量仍然可能导致并发更新,那么最好聚合内存中的统计信息(以线程安全的方式)并定期将它们写入数据库。
答案 1 :(得分:0)
这听起来像是一种有效的方法:
Hibernate在刷新时检查实例版本,如果检测到并发修改则抛出异常。开发人员可以捕获并处理此异常。常见选项是用户合并更改或使用非陈旧数据重新启动业务对话的机会。
您还可以查看将IsolationLevel设置为SERIALIZED或锁定表格行。
另一个选项可能是分离对象,使用统计信息更新它并使用Scheduler等重新附加(更新)它。但是,这可能需要同步您的服务方法(更新统计信息),并且由于此服务可能已被代理,因此我认为不可能同步它。