I have an application which requires certain key objects to be acquired at various different points by calling this method, assigning a Unique Persistent Object to every given Natural ID:
public AddressKeyEntity getAddressKeyEntity(AddressKeyEntity addressKey) {
AddressKeyEntity item = sessionFactory.getCurrentSession().byNaturalId(AddressKeyEntity.class)
.using("address", addressKey.getAddress())
.using("city", addressKey.getCity())
.using("state", addressKey.getState())
.using("zip", addressKey.getZip())
.with(LockOptions.UPGRADE.setTimeOut(LockOptions.WAIT_FOREVER))
.load();
if(item != null) {
return item;
} else {
sessionFactory.getCurrentSession().persist(addressKey);
return addressKey;
}
}
This works great when the application is running in a single-thread or just not very busy. Unfortunately, as soon as I try to run a heavy load through multiple threads, it fails miserably with some combination of unique contraint violation
or org.hibernate.PessimisticLockException
. Sometimes also seeing org.h2.jdbc.JdbcSQLException: Timeout trying to lock table
, which is strange considering the LockOptions.WAIT_FOREVER
. (Maybe it's an H2 bug)
Can this be solved through the Hibernate APIs, without resorting to low-level database features?
All major databases support some variant of insert if not exists atomically returning a unique ID, so I imagine there must be an idiomatic equivalent in Hibernate.