|
|
|
Yeah, i only just saw your message and i was reminded of a similar problem we had once in hibernate and investigated that further during the day..
Because of the presence if so many concurrent sessions, the only way to atomically update something like a counter where there may be many contending threads attempting to increment, was to relinquish control to the database. We solved by def update = sessionFactory.currentSession.createSQLQuery("update foo set counter = counter + 1 where id = 123") Graeme,
I'm using postgres and driving my application via HTTP Unit from multiple threads and locking still doesn't work as advertised. From http://grails.org/doc/1.0.x/guide/single.html#5.3.5%20Pessimistic%20and%20Optimistic%20Locking In Grails pessimistic locking is performed via the lock method: def airport = Airport.get(10) When I follow this pattern the result is multiple OptimisticLockingFailureExceptions Your suggestion of doing airport.lock(10) results in No signature of method: Person.lock() is applicable for argument types: (java.lang.String) values: {"ff80818119bdf60d0119bdf7d5c80005"} (The id is a String since we're using uuid) FYI I believe the reason airport.lock() doesn't work is because according to the hibernate docs, if "airport" has already been loaded in the session, then lock() does a version check - which may fail under concurrency. The workaround is it evict airport from the session then re-obtain it using session.load(clazz, id, LockMode.UPGRADE), e.g.
def session = sessionFactory.currentSession This seems to work OK |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
First for Grails:
1) The HSQLDB database shipped with Grails doesn't support "SELECT .. FOR UPDATE" and hence pessimistic locking is not possible (see http://hsqldb.org/doc/src/org/hsqldb/jdbc/jdbcStatement.html#setCursorName(java.lang.String
)). I have updated the documentation to reflect this.
2) Even on a database where SELECT .. FOR UPDATE is possible like MySQL you may still get a problem with data loss as you're doing an initial get and then a later lock:
In between the time it takes to do the get and call the lock() method another thread could have obtained and locked the db done its changes and you end up with data loss. To avoid this situation I've added a static lock method so you can do:
However, even with this change you test will not pass. Why? because the test shares the same Hibernate session even across all the threads, so essentially its locking on the same object. In Grails different requests will have different sessions bound to each thread which where each willl have a different object to lock on.