44 */
55package org .hibernate .orm .test .batch ;
66
7- import java .util .List ;
8- import java .util .Map ;
9- import java .util .concurrent .ExecutionException ;
10- import java .util .concurrent .ExecutorService ;
11- import java .util .concurrent .Executors ;
12-
7+ import jakarta .persistence .Entity ;
8+ import jakarta .persistence .Id ;
9+ import jakarta .persistence .OptimisticLockException ;
1310import jakarta .persistence .RollbackException ;
11+ import jakarta .persistence .Version ;
1412import org .hibernate .cfg .AvailableSettings ;
1513import org .hibernate .dialect .CockroachDialect ;
16-
14+ import org . hibernate . dialect . Dialect ;
1715import org .hibernate .dialect .MariaDBDialect ;
18- import org .hibernate .testing .junit4 .BaseNonConfigCoreFunctionalTestCase ;
19- import org .junit .Test ;
16+ import org .hibernate .testing .orm .junit .DomainModel ;
17+ import org .hibernate .testing .orm .junit .ServiceRegistry ;
18+ import org .hibernate .testing .orm .junit .SessionFactory ;
19+ import org .hibernate .testing .orm .junit .SessionFactoryScope ;
20+ import org .hibernate .testing .orm .junit .Setting ;
21+ import org .junit .jupiter .api .Test ;
2022
21- import jakarta . persistence . Entity ;
22- import jakarta . persistence . Id ;
23- import jakarta . persistence . OptimisticLockException ;
24- import jakarta . persistence . Version ;
23+ import java . util . List ;
24+ import java . util . concurrent . ExecutionException ;
25+ import java . util . concurrent . ExecutorService ;
26+ import java . util . concurrent . Executors ;
2527
26- import static org .hibernate . testing . transaction . TransactionUtil . doInHibernate ;
27- import static org .junit .Assert . assertEquals ;
28- import static org .junit .Assert . assertTrue ;
29- import static org .junit .Assert .fail ;
28+ import static org .assertj . core . api . Assertions . assertThat ;
29+ import static org .hibernate . testing . orm . junit .DialectContext . getDialect ;
30+ import static org .junit .jupiter . api . Assertions . assertThrows ;
31+ import static org .junit .jupiter . api . Assertions .fail ;
3032
3133/**
3234 * @author Vlad Mihalcea
3335 */
34- public class BatchOptimisticLockingTest extends
35- BaseNonConfigCoreFunctionalTestCase {
36+ @ DomainModel (
37+ annotatedClasses = {
38+ BatchOptimisticLockingTest .Person .class
39+ }
40+ )
41+ @ SessionFactory
42+ @ ServiceRegistry (
43+ settings = {
44+ @ Setting (name = AvailableSettings .STATEMENT_BATCH_SIZE , value = "2" ),
45+ @ Setting (name = AvailableSettings .DIALECT_NATIVE_PARAM_MARKERS , value = "false" )
46+ }
47+ )
48+ public class BatchOptimisticLockingTest {
3649
3750 private final ExecutorService executorService = Executors .newSingleThreadExecutor ();
3851
39- @ Override
40- protected Class <?>[] getAnnotatedClasses () {
41- return new Class <?>[]{
42- Person .class ,
43- };
44- }
45-
46- @ Override
47- protected void addSettings (Map <String ,Object > settings ) {
48- settings .put ( AvailableSettings .STATEMENT_BATCH_SIZE , String .valueOf ( 2 ) );
49- settings .put ( AvailableSettings .DIALECT_NATIVE_PARAM_MARKERS , Boolean .FALSE );
50- }
5152
5253 @ Test
53- public void testBatchAndOptimisticLocking () {
54- doInHibernate ( this :: sessionFactory , session -> {
54+ public void testBatchAndOptimisticLocking (SessionFactoryScope scope ) {
55+ scope . inTransaction ( session -> {
5556 Person person1 = new Person ();
5657 person1 .id = 1L ;
5758 person1 .name = "First" ;
@@ -69,58 +70,49 @@ public void testBatchAndOptimisticLocking() {
6970
7071 } );
7172
72- try {
73- inTransaction ( session -> {
74- List <Person > persons = session
75- .createSelectionQuery ( "select p from Person p" , Person .class )
76- .getResultList ();
77-
78- for ( int i = 0 ; i < persons .size (); i ++ ) {
79- Person person = persons .get ( i );
80- person .name += " Person" ;
81-
82- if ( i == 1 ) {
83- try {
84- executorService .submit ( () -> {
85- doInHibernate ( this ::sessionFactory , _session -> {
86- Person _person = _session .find ( Person .class , person .id );
87- _person .name += " Person is the new Boss!" ;
88- } );
89- } ).get ();
90- }
91- catch (InterruptedException |ExecutionException e ) {
92- fail (e .getMessage ());
93- }
73+ Exception exception = assertThrows ( Exception .class , () -> scope .inTransaction ( session -> {
74+ List <Person > persons = session
75+ .createSelectionQuery ( "select p from Person p" , Person .class )
76+ .getResultList ();
77+
78+ for ( int i = 0 ; i < persons .size (); i ++ ) {
79+ Person person = persons .get ( i );
80+ person .name += " Person" ;
81+
82+ if ( i == 1 ) {
83+ try {
84+ executorService .submit ( () -> {
85+ scope .inTransaction ( _session -> {
86+ Person _person = _session .find ( Person .class , person .id );
87+ _person .name += " Person is the new Boss!" ;
88+ } );
89+ } ).get ();
90+ }
91+ catch (InterruptedException | ExecutionException e ) {
92+ fail ( e .getMessage () );
9493 }
9594 }
96- } );
95+ }
96+ } ) );
97+
98+ Dialect dialect = scope .getSessionFactory ().getJdbcServices ().getDialect ();
99+ if ( dialect instanceof CockroachDialect ) {
100+ // CockroachDB always runs in SERIALIZABLE isolation, and uses SQL state 40001 to indicate
101+ // serialization failure. The failure is mapped to a RollbackException.
102+ assertThat ( exception ).isInstanceOf ( RollbackException .class );
103+ var msg = "could not execute batch" ;
104+ assertThat ( exception .getMessage () ).contains ( msg );
97105 }
98- catch (Exception expected ) {
99- if ( getDialect () instanceof CockroachDialect ) {
100- // CockroachDB always runs in SERIALIZABLE isolation, and uses SQL state 40001 to indicate
101- // serialization failure. The failure is mapped to a RollbackException.
102- assertEquals ( RollbackException .class , expected .getClass () );
103- var msg = "could not execute batch" ;
104- assertEquals (
105- msg ,
106- expected .getMessage ().substring ( 0 , msg .length () )
107- );
106+ else {
107+ assertThat ( exception ).isInstanceOf ( OptimisticLockException .class );
108+
109+ if ( dialect instanceof MariaDBDialect && getDialect ().getVersion ().isAfter ( 11 , 6 , 2 ) ) {
110+ assertThat ( exception .getMessage () ).contains ( "Record has changed since last read in table 'Person'" );
111+
108112 }
109113 else {
110- assertEquals ( OptimisticLockException .class , expected .getClass () );
111-
112- if ( getDialect () instanceof MariaDBDialect && getDialect ().getVersion ().isAfter ( 11 , 6 , 2 )) {
113- assertTrue (
114- expected .getMessage ()
115- .contains ( "Record has changed since last read in table 'Person'" )
116- );
117- } else {
118- assertTrue (
119- expected .getMessage ()
120- .startsWith (
121- "Batch update returned unexpected row count from update 1 (expected row count 1 but was 0) [update Person set name=?,version=? where id=? and version=?]" )
122- );
123- }
114+ assertThat ( exception .getMessage () ).startsWith (
115+ "Batch update returned unexpected row count from update 1 (expected row count 1 but was 0) [update Person set name=?,version=? where id=? and version=?]" );
124116 }
125117 }
126118 }
0 commit comments