simple design question about optimistic locking in spring/jpa/hibernate
I have an object GeneralKnowledgeTest and it contains a lot of statistics fields (ratingsCount, responsesCount, ra开发者_如何学JAVAtingStars ...) 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...
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.
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.
精彩评论