Reputation: 555
I have the same module that connect with database running in two servers (back and front). Its connect with the same database.
I use JPA (Hibernate implementation) and Spring transaction management.
I have the following problem:
I have to update the fieldA from tableA with the MAX value + 1 of two different fields (fieldA from tableA, fieldB from tableB)
Case1:
Before update
tableA fA = 100
tableB fB = 102
After update
tableA fA = 103
tableB fB = 102
Case2:
Before update
tableA fA = 102
tableB fB = 100
After update
tableA fA = 103
tableB fB = 100
The method with this code is transactional and do things before (like create the entity) and after that. So before commit the transaction if the other application try to get the value, it will be outdated and it will save the same value in fieldA. Hibernate sessions are different because the distributed system.
I can't use sequences in database (legal issues because it is about invoicing) or distributed cache for Hibernate (system issues)
How i can do that??
thanks
Upvotes: 1
Views: 1726
Reputation: 61538
You can use locking for that. The appropriate type of locking depends on your use case.
If the probability of a concurrent update is low, use optimistic locking. In case of an update collision, catch the Exception
, refresh the entity, reapply your changes and retry the commit.
If you use optimistic locking, it is advised to add a @Version
field to your entity. Optimistic locking without a version field is not guaranteed to be supported.
If the probability of a concurrent modification is high, use pessimistic locking. Thus you can serialize writes on the row. Note that this type of locking can create a bottleneck as transactions queue for updates and other transactions time out before acquiring the lock.
In order to minimize the lokc time, you can apply the lock on an individual query:
query.setLockMode(LockMode.WRITE)
EDIT: The locks can be probably used in a distributed environment safely.
Optimistic locking is implemented as a check on the @Version
field in the DB at commit time (or equivalent) - with read-commited isolation (the default) there is no risk of missing a committed change to the entity.
Pessimistic locking is implemented on DB level, often using SELECT FOR UPDATE
or similar. So you don't have to worry.
Upvotes: 3
Reputation: 6944
I don't know if I understood correctly your question but maybe in your DAO you can prepare a method where you can do something this
DetachedCriteria dc = DetachedCriteria.forClass(ClassA);
dc.setProjection(Projections.max("id"));
logger.info(svc.getMax(dc));
Once you got the max value you can update the other table
Angelo
Upvotes: 0
Reputation: 16844
You need pesimistic locking. With Hibernate you can do this on the JDBC or transaction level.
Read the chapter about locking in the hibernate manual.
Upvotes: 1