55 */
66package org .hibernate .reactive ;
77
8+ import org .hibernate .LockMode ;
9+ import org .hibernate .boot .registry .StandardServiceRegistryBuilder ;
10+ import org .hibernate .cfg .Configuration ;
11+ import org .hibernate .reactive .testing .SqlStatementTracker ;
12+
813import java .util .ArrayList ;
914import java .util .Collection ;
1015import java .util .List ;
1116import java .util .concurrent .TimeUnit ;
1217
18+ import org .junit .jupiter .api .BeforeEach ;
1319import org .junit .jupiter .api .Test ;
1420
1521import io .vertx .junit5 .Timeout ;
2228import jakarta .persistence .OneToMany ;
2329
2430import static org .assertj .core .api .Assertions .assertThat ;
31+ import static org .hibernate .reactive .containers .DatabaseConfiguration .dbType ;
2532
2633@ Timeout (value = 10 , timeUnit = TimeUnit .MINUTES )
2734public class FindByIdWithLockTest extends BaseReactiveTest {
2835 private static final Long CHILD_ID = 1L ;
2936
37+ private static SqlStatementTracker sqlTracker ;
38+
39+ @ Override
40+ protected Configuration constructConfiguration () {
41+ Configuration configuration = super .constructConfiguration ();
42+
43+ // Construct a tracker that collects query statements via the SqlStatementLogger framework.
44+ // Pass in configuration properties to hand off any actual logging properties
45+ sqlTracker = new SqlStatementTracker ( FindByIdWithLockTest ::selectQueryFilter , configuration .getProperties () );
46+ return configuration ;
47+ }
48+
49+ @ BeforeEach
50+ public void clearTracker () {
51+ sqlTracker .clear ();
52+ }
53+
54+ @ Override
55+ protected void addServices (StandardServiceRegistryBuilder builder ) {
56+ sqlTracker .registerService ( builder );
57+ }
58+
59+ private static boolean selectQueryFilter (String s ) {
60+ return s .toLowerCase ().startsWith ( "select " );
61+ }
62+
3063 @ Override
3164 protected Collection <Class <?>> annotatedEntities () {
3265 return List .of ( Parent .class , Child .class );
@@ -50,6 +83,44 @@ context, getMutinySessionFactory()
5083 );
5184 }
5285
86+ @ Test
87+ public void testFindUpgradeNoWait (VertxTestContext context ) {
88+ Child child = new Child ( CHILD_ID , "And" );
89+ test (
90+ context , getMutinySessionFactory ()
91+ .withTransaction ( session -> session .persistAll ( child ) )
92+ .invoke ( () -> sqlTracker .clear () )
93+ .chain ( () -> getMutinySessionFactory ().withTransaction ( session -> session
94+ .find ( Child .class , CHILD_ID , LockMode .UPGRADE_NOWAIT )
95+ .invoke ( c -> {
96+ assertThat ( c ).isNotNull ();
97+ assertThat ( c .getId () ).isEqualTo ( CHILD_ID );
98+ String selectQuery = sqlTracker .getLoggedQueries ().get ( 0 );
99+ assertThat ( sqlTracker .getLoggedQueries () ).hasSize ( 1 );
100+ assertThat ( selectQuery )
101+ .matches ( this ::noWaitLockingPredicate , "SQL query with nowait lock for " + dbType ().name () );
102+ }
103+ ) ) )
104+ );
105+ }
106+
107+ /**
108+ * @return true if the query contains the expected nowait keyword for the selected database
109+ */
110+ private boolean noWaitLockingPredicate (String selectQuery ) {
111+ return switch ( dbType () ) {
112+ case POSTGRESQL -> selectQuery .endsWith ( "for no key update of c1_0 nowait" );
113+ case COCKROACHDB -> selectQuery .endsWith ( "for update of c1_0 nowait" );
114+ case SQLSERVER -> selectQuery .contains ( "with (updlock,holdlock,rowlock,nowait)" );
115+ case ORACLE -> selectQuery .contains ( "for update of c1_0.id nowait" );
116+ // DB2 does not support nowait
117+ case DB2 -> selectQuery .contains ( "for read only with rs use and keep update locks" );
118+ case MARIA -> selectQuery .contains ( "for update nowait" );
119+ case MYSQL -> selectQuery .contains ( "for update of c1_0 nowait" );
120+ default -> throw new IllegalArgumentException ( "Database not recognized: " + dbType ().name () );
121+ };
122+ }
123+
53124 @ Entity (name = "Parent" )
54125 public static class Parent {
55126
@@ -59,7 +130,7 @@ public static class Parent {
59130 private String name ;
60131
61132 @ OneToMany (fetch = FetchType .EAGER )
62- public List <Child > children ;
133+ public List <Child > children = new ArrayList <>() ;
63134
64135 public Parent () {
65136 }
@@ -70,9 +141,6 @@ public Parent(Long id, String name) {
70141 }
71142
72143 public void add (Child child ) {
73- if ( children == null ) {
74- children = new ArrayList <>();
75- }
76144 children .add ( child );
77145 }
78146
@@ -89,7 +157,6 @@ public List<Child> getChildren() {
89157 }
90158 }
91159
92-
93160 @ Entity (name = "Child" )
94161 public static class Child {
95162
@@ -109,13 +176,6 @@ public Child(Long id, String name) {
109176 this .name = name ;
110177 }
111178
112- public Child (Long id , String name , Parent parent ) {
113- this .id = id ;
114- this .name = name ;
115- this .parent = parent ;
116- parent .add ( this );
117- }
118-
119179 public Long getId () {
120180 return id ;
121181 }
@@ -128,6 +188,4 @@ public Parent getParent() {
128188 return parent ;
129189 }
130190 }
131-
132-
133191}
0 commit comments