[hibernate-dev] Possible regression on master
Vlad Mihalcea
mihalcea.vlad at gmail.com
Tue May 17 08:32:40 EDT 2016
Hi,
While fixing tests for Oracle after rebasing my branch, I realized that the
org.hibernate.test.optlock.OptimisticLockTest > testOptimisticLockAllDelete
fails on Oracle10gDialect, while running just fine on H2.
When reaching the following branching logic in AbstractEntityPersister:
if ( useBatch ) {
session.getJdbcCoordinator().getBatch( deleteBatchKey ).addToBatch();
}
else {
check(
session.getJdbcCoordinator().getResultSetReturn().executeUpdate( delete ),
id,
j,
expectation,
delete
);
}
If using H2, we go to the useBatch branch, while for Oracle dialects that
are less than 12c (hibernate.jdbc.batch_versioned_data is set to false,
therefore JDBC batching is disabled) it goes on the second branch logic.
This way, for H2, a StaleStateException is thrown and the flush operation
flow is disrupted.
For Oracle, the check method call will throw a StaleObjectStateException
instead:
catch (StaleStateException e) {
if ( !isNullableTable( tableNumber ) ) {
if ( getFactory().getStatistics().isStatisticsEnabled() ) {
getFactory().getStatisticsImplementor()
.optimisticFailure( getEntityName() );
}
throw new StaleObjectStateException( getEntityName(), id );
}
return false;
}
Now, there is a difference between how the ExceptionConverterImpl handles
StaleStateException and StaleObjectStateException because for the latter,
it tries to fetch the entity in question:
final Object entity = sharedSessionContract.load( sose.getEntityName(),
identifier );
Because there is no proxy loaded in the current Session, the
DefaultLoadEntityListener will execute the createProxyIfNecessary method,
and because the entity was deleted, it will return null:
EntityEntry entry = persistenceContext.getEntry( existing );
Status status = entry.getStatus();
if ( status == Status.DELETED || status == Status.GONE ) {
return null;
}
However, getReference() throws an exception when there is no object being
found:
getFactory().getEntityNotFoundDelegate().handleEntityNotFound(
entityPersister.getEntityName(),
id
);
So instead of a StaleObjectStateException, we get
an ObjectNotFoundException.
One quick fix is to just catch that ObjectNotFoundException:
Object entity;
try {
entity = sharedSessionContract.load( sose.getEntityName(), identifier );
} catch(ObjectNotFoundException e) {
entity = null;
}
if ( entity instanceof Serializable ) {
//avoid some user errors regarding boundary crossing
pe = new OptimisticLockException( e.getMessage(), e, entity );
}
else {
pe = new OptimisticLockException( e.getMessage(), e );
}
Or maybe there is some other fix that you might think of.
Vlad
More information about the hibernate-dev
mailing list