Let's see it on an example query.
Hibernate uses the version property in the WHERE clause of the executing UPDATE statement:
UPDATE
test
SET
name = :newName,
version = :existVersion + 1
WHERE
id = :id AND version = :existVersion
So, if version = :existVersion
doesn't match, then a StaleStateExcetion
is thrown, which will be wrapped in a JPA OptimisticLockException
when bootstrapping Hibernate using JPA.
Let's consider we have a entity like that:
class Test {
Long id;
String name;
int version;
}
For this Test
class, on update operation. To check version, we can follow different strategies:
- we can manually check versions:
update(Test request) {
Test exist = repository.findById(request.id);
if (exist.version != request.version) throw Exception();
...
}
Pros
it looks performant because of no-extra-db-callCons
but extrabusiness-check
and extraif-check
- we can directly send version to db and optimistic-lock handles it.
@Transactional
update(Test request) {
Test exist = repository.findById(request.id);
exist.setName(request.name);
exist.setVersion(request.version);
repository.update(exist);
}
- This doesn't work. "Trying to set the version of an entity to a specific value is a mistake because the default optimistic locking mechanism does not take into consideration the version from the entity Java object but from the loading-time snapshot."
- if we don't use
Transaction
, it works but not practical.
- secure-key and manual-update
Let's assume, we have a version field in
UUID
format so in this case we couldn't benefit from hibernate@Version
because hibernate supports onlyint
andtimestamp
for version-field.
update(Test request) {
Test exist = repository.findById(request.id);
if (exist.version != request.version) throw Exception();
exist.setVersion(new UUID...);
repository.customUpdate(exist, request.version);
...
}
Cons
custom update-query for each entity. and manual version control.Pros
it is secure but do we really need this security? it looks like over-engineering.
- secure-key and version
Let's assume, we have a secure-key field in
UUID
and hibernate version but request/response doesn't know version.
update(Test request) {
Test exist = repository.findById(request.id);
if (exist.secureKey != request.secureKey) throw Exception();
exist.setSecureKey(new UUID...);
repository.update(exist);
...
}
Cons
but extrabusiness-check
and extraif-check
Pros
it is secure but do we really need this security? it looks like over-engineering.