Skip to content

Commit 0c6ff81

Browse files
dreab8DavideD
authored andcommitted
[#2534] Add test for session.find() will not respect NOWAIT locks starting from HR 3.1
1 parent 1b3f0f6 commit 0c6ff81

File tree

1 file changed

+72
-14
lines changed

1 file changed

+72
-14
lines changed

hibernate-reactive-core/src/test/java/org/hibernate/reactive/FindByIdWithLockTest.java

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,17 @@
55
*/
66
package 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+
813
import java.util.ArrayList;
914
import java.util.Collection;
1015
import java.util.List;
1116
import java.util.concurrent.TimeUnit;
1217

18+
import org.junit.jupiter.api.BeforeEach;
1319
import org.junit.jupiter.api.Test;
1420

1521
import io.vertx.junit5.Timeout;
@@ -22,11 +28,38 @@
2228
import jakarta.persistence.OneToMany;
2329

2430
import static org.assertj.core.api.Assertions.assertThat;
31+
import static org.hibernate.reactive.containers.DatabaseConfiguration.dbType;
2532

2633
@Timeout(value = 10, timeUnit = TimeUnit.MINUTES)
2734
public 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

Comments
 (0)