why NonBatchingBatcher doesn’t re throw a StaleObjectStateException

Description

Got questions in hibernate code and trying to understand why it is so. In short, the OptimisticLockException is thrown without the entity in it when I upgraded to Hibernate 5x (5.0.4.Final) from 3x ( 3.3.2.GA) version.

The questions upfront without any background information:
1.why "jdbcBatchVersionedData" enabled by default to true in latest versions ? And from which Hibernate version onwards?
2.Why the non NonBatchingBatcher#expectation.verifyOutcome() doesn’t re throw a StaleObjectStateException with entity information even though it calls same "verifyOutcome()" as in "AbstractEntityPersister#check()

Let me explain my observations and please correct me if my below understanding is wrong.

So , my application test case is to update a versioned entity with an invalid version. I just change the version in between on purpose and it is excepted to fail with a zero row count. In our scenario it will throw a "StaleStateException" from Expectation#checkNonBatched() with a message:

1 "Unexpected row count: 0 ; expected: 1"

This exception eventually get wrapped in OptimisticLockException and I am good with that, I get the entity from exception and able to perform necessary assertions on that.

Now, after uplifting to Hibernate 5x, its thrown from Expectation#checkBatched(). With message :

1 "Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1".

Reason being hibernate decides to switch to batch mode for versioned entity update(AbstractEntityPersister#isBatchable()). The single deciding factor in my flow is jdbcBatchVersionedData is turned on by default to true in 5x(5.0.4.Final). But it is false by default in version 3x (3.3.2.GA). Here is the snippet from both versions for easy reference.

SettingsFactory in Version 3.3.2.GA:

1 boolean jdbcBatchVersionedData = PropertiesHelper.getBoolean(Environment.BATCH_VERSIONED_DATA, properties, false);

SessionFactoryOptionsStateStandardImpl in 5.0.4.Final :

1 this.jdbcBatchVersionedData = ConfigurationHelper.getBoolean( BATCH_VERSIONED_DATA, configurationSettings, true );

So first question is why this enabled by default to true in latest versions ? And from which Hibernate version onwards?

Next question is about entity not attached in the exception. Now, it is about to decide batching in AbstractEntityPersister#update(), the flow goes to

1 2 3 4 5 6 7 if ( useBatch ) { session.getBatcher().addToBatch( expectation ); return true; } else { return check( update.executeUpdate(), id, j, expectation, update ); }
1 2 3 4 5 public void addToBatch(Expectation expectation) throws SQLException, HibernateException { PreparedStatement statement = getStatement(); final int rowCount = statement.executeUpdate(); expectation.verifyOutcome( rowCount, statement, 0 ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 protected boolean check(int rows, Serializable id, int tableNumber, Expectation expectation, PreparedStatement statement) throws HibernateException { try { expectation.verifyOutcome( rows, statement, -1 ); } catch( StaleStateException e ) { if ( !isNullableTable( tableNumber ) ) { if ( getFactory().getStatistics().isStatisticsEnabled() ) { getFactory().getStatisticsImplementor() .optimisticFailure( getEntityName() ); } throw new StaleObjectStateException( getEntityName(), id ); } return false; } //...

If useBatch is false the flow goes to "check()" and "expectation.verifyOutcome()" is getting called. Here it will catch StaleStateException and StaleObjectStateException re-thrown with entity name and identifier. This is what is happening for my test with hibernate 3X

If it’s a batch the call goes to "NonBatchingBatcher", because I didn’t specify any batch size in my environment and its zero by default. Then the same "expectation.verifyOutcome()" in addToBatch() throws the StaleStateException, from checkBatched(). The exception propagates and it will get wrapped in AbstractEntityManagerImpl#wrapStaleStateException(). But without any entity information.

So why the non NonBatchingBatcher#expectation.verifyOutcome() doesn’t re throw a StaleObjectStateException with entity information even though it calls same "verifyOutcome()" as in "check()"? What are my options here to deal with this situation if I need the entity attached in the exception?

Appreciate your attention and thank you for any help.

Environment

None

Status

Assignee

Unassigned

Reporter

John Mathew

Fix versions

None

Labels

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Affects versions

5.0.4
3.3.2

Priority

Major