Skip to content

Commit a106c70

Browse files
committed
HHH-18621 Restore hibernate.jdbc.batch_versioned_data function.
It, particularly, enables reporting the exact entity that failed optimistic lock.
1 parent d79c739 commit a106c70

File tree

2 files changed

+76
-1
lines changed

2 files changed

+76
-1
lines changed

hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/AbstractMutationCoordinator.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ protected BatchKeyAccess resolveBatchKeyAccess(boolean dynamicUpdate, SharedSess
6868
if ( !dynamicUpdate
6969
&& !entityPersister().optimisticLockStyle().isAllOrDirty()
7070
&& session.getTransactionCoordinator() != null
71-
&& session.getTransactionCoordinator().isTransactionActive() ) {
71+
&& session.getTransactionCoordinator().isTransactionActive()
72+
&& (
73+
session.getSessionFactory().getSessionFactoryOptions().isJdbcBatchVersionedData()
74+
|| !entityPersister().isVersioned() ) ) {
7275
return this::getBatchKey;
7376
}
7477

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package org.hibernate.orm.test.batch;
2+
3+
import java.io.Serializable;
4+
import java.util.List;
5+
6+
import org.hibernate.cfg.BatchSettings;
7+
8+
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
9+
import org.hibernate.testing.orm.junit.JiraKey;
10+
import org.hibernate.testing.orm.junit.Jpa;
11+
import org.hibernate.testing.orm.junit.Setting;
12+
import org.junit.jupiter.api.Assertions;
13+
import org.junit.jupiter.api.Test;
14+
15+
import jakarta.persistence.Entity;
16+
import jakarta.persistence.GeneratedValue;
17+
import jakarta.persistence.GenerationType;
18+
import jakarta.persistence.Id;
19+
import jakarta.persistence.OptimisticLockException;
20+
import jakarta.persistence.RollbackException;
21+
import jakarta.persistence.Version;
22+
23+
@Jpa(
24+
annotatedClasses = BatchOffOnlyForOptimisticallyLocked.Something.class,
25+
properties = {
26+
@Setting(name = BatchSettings.STATEMENT_BATCH_SIZE, value = "10"),
27+
@Setting(name = BatchSettings.BATCH_VERSIONED_DATA, value = "false")
28+
}
29+
)
30+
@JiraKey( "HHH-18621" )
31+
public class BatchOffOnlyForOptimisticallyLocked {
32+
@Test
33+
public void testMultiUpdateOfConcurrentlyModified(EntityManagerFactoryScope scope) {
34+
scope.inTransaction( em -> {
35+
em.persist( new Something( "First" ) );
36+
em.persist( new Something( "Second" ) );
37+
} );
38+
39+
final RollbackException ex = Assertions.assertThrows( RollbackException.class, () -> {
40+
scope.inTransaction( em -> {
41+
final List<Something> subjects = em.createQuery( "select s from Something s", Something.class )
42+
.getResultList();
43+
scope.inTransaction(
44+
competitorEm -> competitorEm.find( Something.class, subjects.get( 0 ).id ).name = "Outrun"
45+
);
46+
for ( Something something : subjects ) {
47+
something.name += " modified";
48+
}
49+
} );
50+
} );
51+
Assertions.assertInstanceOf( OptimisticLockException.class, ex.getCause(), "The cause of rollback" );
52+
Assertions.assertNotNull( ( (OptimisticLockException) ex.getCause() ).getEntity(), "OLE references an entity" );
53+
}
54+
55+
//Has to be Serializable, otherwise it is not deemed safe to include in the OLE.
56+
@Entity(name = "Something")
57+
public static class Something implements Serializable {
58+
@Id
59+
@GeneratedValue(strategy = GenerationType.IDENTITY)
60+
public Long id;
61+
public String name;
62+
@Version
63+
public long version;
64+
65+
public Something() {
66+
}
67+
68+
public Something(String name) {
69+
this.name = name;
70+
}
71+
}
72+
}

0 commit comments

Comments
 (0)