2011-03-01 53 views
1

我有一个对象GeneralKnowledgeTest,它包含很多统计字段(ratingsCount,responsesCount,ratingStars ...),每更新一次用户都会进行测试takeTest() - >事务性方法)。简单的设计问题关于乐观锁定在spring/jpa/hibernate

这可能会发生,很多用户正在以相同的时间相同的测试,所以我想实现一个乐观锁(@version)和重试takeTest方法情况下的乐观锁定异常被抛出AA拦截。

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

您对此程序有什么看法?对于可能有很多用户试图进行相同测试的系统,这是否是实现乐观锁定的好方法?

PS。业务不会承认显示任何警告消息,以防乐观锁异常被抛出,因此拦截器是一个必须允许顺利执行...

回答

0

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

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

+0

许多用户很可能在同一时间内完成测试(如当天测试等)。我已经读过乐观锁定在性能方面没问题,所以没有数据库锁定。 (设想100个用户在同一时间内完成相同的测试,同时考虑takeTest是一个复杂的方法,创建许多额外的数据库对象,使交易花费更长时间)。但是一般来说,我认为这有什么不妥之处?是否有任何错误或缺点?预先感谢您 – 2011-03-01 21:02:04

+0

不,没有错误。乐观锁定失败将导致数据被重新读取,但会增加数据库负载,并且重做测试逻辑会增加CPU负载。这种方法没有问题,只取决于您希望锁定失败的频率。 – Will 2011-03-01 21:29:58

0

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

休眠检查对象实例的版本在冲洗时间,如果检测到的并发修改抛出异常。这是由开发人员抓住并处理这个异常。常用选项是用户合并更改或重新启动与非陈旧数据的业务对话的机会。

你也可以看看将IsolationLevel设置为SERIALIZED或锁定表格行。

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