HHH-18621 Restore hibernate.jdbc.batch_versioned_data function.

It, particularly, enables reporting the exact entity that failed optimistic lock.
This commit is contained in:
ettavolt 2024-08-31 19:22:12 -04:00
parent 417eb89369
commit 681dc7c9bb
2 changed files with 76 additions and 1 deletions

View File

@ -69,7 +69,10 @@ public abstract class AbstractMutationCoordinator {
if ( !dynamicUpdate
&& !entityPersister().optimisticLockStyle().isAllOrDirty()
&& session.getTransactionCoordinator() != null
&& session.getTransactionCoordinator().isTransactionActive() ) {
&& session.getTransactionCoordinator().isTransactionActive()
&& (
session.getSessionFactory().getSessionFactoryOptions().isJdbcBatchVersionedData()
|| !entityPersister().isVersioned() ) ) {
return this::getBatchKey;
}

View File

@ -0,0 +1,72 @@
package org.hibernate.orm.test.batch;
import java.io.Serializable;
import java.util.List;
import org.hibernate.cfg.BatchSettings;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.Jpa;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OptimisticLockException;
import jakarta.persistence.RollbackException;
import jakarta.persistence.Version;
@Jpa(
annotatedClasses = BatchOffOnlyForOptimisticallyLocked.Something.class,
properties = {
@Setting(name = BatchSettings.STATEMENT_BATCH_SIZE, value = "10"),
@Setting(name = BatchSettings.BATCH_VERSIONED_DATA, value = "false")
}
)
@JiraKey( "HHH-18621" )
public class BatchOffOnlyForOptimisticallyLocked {
@Test
public void testMultiUpdateOfConcurrentlyModified(EntityManagerFactoryScope scope) {
scope.inTransaction( em -> {
em.persist( new Something( "First" ) );
em.persist( new Something( "Second" ) );
} );
final RollbackException ex = Assertions.assertThrows( RollbackException.class, () -> {
scope.inTransaction( em -> {
final List<Something> subjects = em.createQuery( "select s from Something s", Something.class )
.getResultList();
scope.inTransaction(
competitorEm -> competitorEm.find( Something.class, subjects.get( 0 ).id ).name = "Outrun"
);
for ( Something something : subjects ) {
something.name += " modified";
}
} );
} );
Assertions.assertInstanceOf( OptimisticLockException.class, ex.getCause(), "The cause of rollback" );
Assertions.assertNotNull( ( (OptimisticLockException) ex.getCause() ).getEntity(), "OLE references an entity" );
}
//Has to be Serializable, otherwise it is not deemed safe to include in the OLE.
@Entity(name = "Something")
public static class Something implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Long id;
public String name;
@Version
public long version;
public Something() {
}
public Something(String name) {
this.name = name;
}
}
}