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 .containers .DatabaseConfiguration ;
12+ import org .hibernate .reactive .testing .SqlStatementTracker ;
13+
814import java .util .ArrayList ;
915import java .util .Collection ;
1016import java .util .List ;
1117import java .util .concurrent .TimeUnit ;
1218
19+ import org .junit .jupiter .api .BeforeEach ;
1320import org .junit .jupiter .api .Test ;
1421
1522import io .vertx .junit5 .Timeout ;
2229import jakarta .persistence .OneToMany ;
2330
2431import static org .assertj .core .api .Assertions .assertThat ;
32+ import static org .hibernate .reactive .containers .DatabaseConfiguration .dbType ;
2533
2634@ Timeout (value = 10 , timeUnit = TimeUnit .MINUTES )
2735public class FindByIdWithLockTest extends BaseReactiveTest {
2836 private static final Long CHILD_ID = 1L ;
2937
38+ private static SqlStatementTracker sqlTracker ;
39+
40+ @ Override
41+ protected Configuration constructConfiguration () {
42+ Configuration configuration = super .constructConfiguration ();
43+
44+ // Construct a tracker that collects query statements via the SqlStatementLogger framework.
45+ // Pass in configuration properties to hand off any actual logging properties
46+ sqlTracker = new SqlStatementTracker ( FindByIdWithLockTest ::filter , configuration .getProperties () );
47+ return configuration ;
48+ }
49+
50+ @ BeforeEach
51+ public void clearTracker () {
52+ sqlTracker .clear ();
53+ }
54+
55+ protected void addServices (StandardServiceRegistryBuilder builder ) {
56+ sqlTracker .registerService ( builder );
57+ }
58+
59+ private static boolean filter (String s ) {
60+ String [] accepted = { "select " };
61+ for ( String valid : accepted ) {
62+ if ( s .toLowerCase ().startsWith ( valid ) ) {
63+ return true ;
64+ }
65+ }
66+ return false ;
67+ }
68+
69+
3070 @ Override
3171 protected Collection <Class <?>> annotatedEntities () {
3272 return List .of ( Parent .class , Child .class );
@@ -50,6 +90,43 @@ context, getMutinySessionFactory()
5090 );
5191 }
5292
93+ @ Test
94+ public void testFindUpgradeNoWait (VertxTestContext context ) {
95+ Child child = new Child ( CHILD_ID , "And" );
96+ test (
97+ context , getMutinySessionFactory ()
98+ .withTransaction ( session -> session .persistAll ( child ) )
99+ .invoke ( () -> sqlTracker .clear () )
100+ .chain ( () -> getMutinySessionFactory ().withTransaction ( session -> session
101+ .find ( Child .class , CHILD_ID , LockMode .UPGRADE_NOWAIT )
102+ .invoke ( c -> {
103+ assertThat ( c ).isNotNull ();
104+ assertThat ( c .getId () ).isEqualTo ( CHILD_ID );
105+ String selectQuery = sqlTracker .getLoggedQueries ().get ( 0 );
106+ assertThat ( sqlTracker .getLoggedQueries () ).hasSize ( 1 );
107+ switch ( DatabaseConfiguration .dbType () ) {
108+ case POSTGRESQL -> assertThat ( selectQuery )
109+ .endsWith ( "for no key update of c1_0 nowait" );
110+ case COCKROACHDB -> assertThat ( selectQuery )
111+ .endsWith ( "for update of c1_0 nowait" );
112+ case SQLSERVER -> assertThat ( selectQuery )
113+ .contains ( "with (updlock,holdlock,rowlock,nowait)" );
114+ case ORACLE -> assertThat ( selectQuery )
115+ .contains ( "for update of c1_0.id nowait" );
116+ case DB2 -> assertThat ( selectQuery )
117+ .contains ( "for read only with rs use and keep update locks" ); // DB2 does not support nowait
118+ case MARIA -> assertThat ( selectQuery )
119+ .contains ( "for update nowait" );
120+ case MYSQL -> assertThat ( selectQuery )
121+ .contains ( "for update of c1_0 nowait" );
122+ default -> throw new IllegalArgumentException ( "Database not recognized: " + dbType ().name () );
123+ }
124+ }
125+ ) ) )
126+ );
127+ }
128+
129+
53130 @ Entity (name = "Parent" )
54131 public static class Parent {
55132
0 commit comments