|
23 | 23 | import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
24 | 24 | import org.hibernate.sql.ast.tree.select.SelectStatement;
|
25 | 25 | import org.hibernate.sql.exec.internal.BaseExecutionContext;
|
| 26 | +import org.hibernate.sql.exec.internal.CallbackImpl; |
26 | 27 | import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl;
|
27 | 28 | import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
|
28 | 29 | import org.hibernate.sql.exec.internal.StandardStatementCreator;
|
|
35 | 36 | import org.hibernate.sql.exec.spi.PreAction;
|
36 | 37 | import org.hibernate.sql.exec.spi.StatementAccess;
|
37 | 38 | import org.hibernate.sql.results.spi.SingleResultConsumer;
|
| 39 | +import org.hibernate.testing.orm.junit.DialectFeatureChecks; |
38 | 40 | import org.hibernate.testing.orm.junit.DomainModel;
|
| 41 | +import org.hibernate.testing.orm.junit.RequiresDialectFeature; |
39 | 42 | import org.hibernate.testing.orm.junit.SessionFactory;
|
40 | 43 | import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
41 | 44 | import org.junit.jupiter.api.AfterEach;
|
42 | 45 | import org.junit.jupiter.api.BeforeEach;
|
43 | 46 | import org.junit.jupiter.api.Test;
|
44 | 47 |
|
45 | 48 | import java.sql.Connection;
|
| 49 | +import java.util.ArrayList; |
| 50 | +import java.util.List; |
| 51 | + |
| 52 | +import static org.assertj.core.api.Assertions.assertThat; |
46 | 53 |
|
47 | 54 |
|
48 | 55 | /**
|
@@ -96,14 +103,13 @@ void testSimpleSelect(SessionFactoryScope factoryScope) {
|
96 | 103 | }
|
97 | 104 |
|
98 | 105 | @Test
|
| 106 | + @RequiresDialectFeature( feature = DialectFeatureChecks.SupportsConnectionLockTimeouts.class) |
99 | 107 | void testConnectionLockTimeout(SessionFactoryScope factoryScope) {
|
100 | 108 | final SessionFactoryImplementor sessionFactory = factoryScope.getSessionFactory();
|
101 | 109 |
|
102 | 110 | final LockingSupport lockingSupport = sessionFactory.getJdbcServices().getDialect().getLockingSupport();
|
103 | 111 | final ConnectionLockTimeoutStrategy lockTimeoutStrategy = lockingSupport.getConnectionLockTimeoutStrategy();
|
104 |
| - if ( lockTimeoutStrategy.getSupportedLevel() == ConnectionLockTimeoutStrategy.Level.NONE ) { |
105 |
| - return; |
106 |
| - } |
| 112 | + assert lockTimeoutStrategy.getSupportedLevel() != ConnectionLockTimeoutStrategy.Level.NONE; |
107 | 113 |
|
108 | 114 | final EntityPersister entityDescriptor = sessionFactory.getMappingMetamodel().findEntityDescriptor( Person.class );
|
109 | 115 |
|
@@ -138,6 +144,66 @@ void testConnectionLockTimeout(SessionFactoryScope factoryScope) {
|
138 | 144 | } );
|
139 | 145 | }
|
140 | 146 |
|
| 147 | + @Test |
| 148 | + void testFollowOnLockingParadigm(SessionFactoryScope factoryScope) { |
| 149 | + // NOTE: this just tests the principle - |
| 150 | + // for now, just collect the values loaded. |
| 151 | + // ultimately, this can be used to apply smarter follow-on locking. |
| 152 | + |
| 153 | + final SessionFactoryImplementor sessionFactory = factoryScope.getSessionFactory(); |
| 154 | + final EntityPersister entityDescriptor = sessionFactory.getMappingMetamodel().findEntityDescriptor( Person.class ); |
| 155 | + |
| 156 | + final PersonQuery personQuery = createPersonQuery( entityDescriptor, sessionFactory ); |
| 157 | + final JdbcOperationQuerySelect jdbcOperation = personQuery.jdbcOperation(); |
| 158 | + final JdbcParameterBindings jdbcParameterBindings = personQuery.jdbcParameterBindings(); |
| 159 | + |
| 160 | + factoryScope.inTransaction( (session) -> { |
| 161 | + final LoadedValueCollector loadedValueCollector = new LoadedValueCollector(); |
| 162 | + |
| 163 | + final Callback callback = new CallbackImpl(); |
| 164 | + callback.registerAfterLoadAction( (entity, entityMappingType, session1) -> { |
| 165 | + loadedValueCollector.loadedValues.add( entity ); |
| 166 | + } ); |
| 167 | + |
| 168 | + final SingleIdExecutionContext executionContext = new SingleIdExecutionContext( |
| 169 | + session, |
| 170 | + null, |
| 171 | + 1, |
| 172 | + entityDescriptor, |
| 173 | + QueryOptions.NONE, |
| 174 | + callback |
| 175 | + ); |
| 176 | + |
| 177 | + |
| 178 | + final DatabaseOperationSelectImpl.Builder operationBuilder = DatabaseOperationSelectImpl |
| 179 | + .builder( jdbcOperation ) |
| 180 | + .appendPostAction( loadedValueCollector ); |
| 181 | + |
| 182 | + final ConnectionLockTimeoutStrategy lockTimeoutStrategy = session |
| 183 | + .getDialect() |
| 184 | + .getLockingSupport() |
| 185 | + .getConnectionLockTimeoutStrategy(); |
| 186 | + if ( lockTimeoutStrategy.getSupportedLevel() != ConnectionLockTimeoutStrategy.Level.NONE ) { |
| 187 | + final LockTimeoutHandler lockTimeoutHandler = new LockTimeoutHandler( Timeout.seconds( 2 ), lockTimeoutStrategy ); |
| 188 | + operationBuilder.addSecondaryActionPair( lockTimeoutHandler, lockTimeoutHandler ); |
| 189 | + } |
| 190 | + |
| 191 | + final DatabaseOperationSelectImpl databaseOperation = operationBuilder.build(); |
| 192 | + final Person person = databaseOperation.execute( |
| 193 | + Person.class, |
| 194 | + 1, |
| 195 | + StandardStatementCreator.getStatementCreator( ScrollMode.FORWARD_ONLY ), |
| 196 | + jdbcParameterBindings, |
| 197 | + row -> (Person) row[0], |
| 198 | + SingleResultConsumer.instance(), |
| 199 | + executionContext |
| 200 | + ); |
| 201 | + |
| 202 | + assertThat( loadedValueCollector.loadedValues ).hasSize( 1 ); |
| 203 | + } ); |
| 204 | + |
| 205 | + } |
| 206 | + |
141 | 207 | private static class LockTimeoutHandler implements PreAction, PostAction {
|
142 | 208 | private final ConnectionLockTimeoutStrategy lockTimeoutStrategy;
|
143 | 209 | private final Timeout timeout;
|
@@ -172,6 +238,17 @@ public void performPostAction(StatementAccess jdbcStatementAccess, Connection jd
|
172 | 238 | }
|
173 | 239 | }
|
174 | 240 |
|
| 241 | + private static class LoadedValueCollector implements PostAction { |
| 242 | + private final List<Object> loadedValues = new ArrayList<>(); |
| 243 | + |
| 244 | + @Override |
| 245 | + public void performPostAction(StatementAccess jdbcStatementAccess, Connection jdbcConnection, ExecutionContext executionContext) { |
| 246 | + loadedValues.forEach( (value) -> { |
| 247 | + System.out.printf( "Loaded value: %s\n", value ); |
| 248 | + } ); |
| 249 | + } |
| 250 | + } |
| 251 | + |
175 | 252 |
|
176 | 253 | private PersonQuery createPersonQuery(
|
177 | 254 | EntityPersister entityDescriptor,
|
|
0 commit comments