I found a lot of posts regarding this topic, but all answers were just links to documentations with no example code, i.e., how to use concurrency in practice.
My situation: I have an entity House
with (for simplyfication) two attributes, number
(the id) and owner
. The database is initialized with 10 Houses
with number
1-10 and owner
always null
.
I want to assign a new owner to the house with currently no owner, and the smallest number
. My code looks like this:
@Transactional
void assignNewOwner(String newOwner) {
//this is flagged as @Transactional too
House tmp = houseDao.getHouseWithoutOwnerAndSmallestNumber();
tmp.setOwner(newOwner);
//this is flagged as @Transactional too
houseDao.update(tmp);
}
For my understanding, although the @Transactional
is used, the same House
could be assigned twice to different owners, if two requests fetch the same empty House
as tmp
. How do I ensure this can not happen?
I know, including the update in the selection of the empty House
would solve the issue, but in near future, I want to modify/work with the tmp
object more.
Optimistic
If you add a version column to your entity / table then you could take advantage of a mechanism called Optimistic Locking. This is the most proficient way of making sure that the state of an entity has not changed since we obtained it in a transactional context.
Once you createQuery
using the session
you can then call setLockMode(LockModeType.OPTIMISTIC);
Then, just before the transaction is commited, the persistence provider would query for the current version of that entity and check whether it has been incremented by another transaction. If so, you would get an OptimisticLockException and a transaction rollback.
Pessimistic
If you do not version your rows, then you are left with pessimistic lockin which basically means that you phycically create a lock for queries entities on the database level and other transactions cannot read / update those certain rows.
You achieve that by setting this on the Query
object:
setLockMode(LockModeType.PESSIMISTIC_READ);
or
setLockMode(LockModeType.PESSIMISTIC_WRITE);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With