Skip to content

Commit e0e279e

Browse files
committed
HHH-19551 - Address deficiencies in pessimistic locking
1 parent 8a90a4a commit e0e279e

File tree

175 files changed

+4339
-2202
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

175 files changed

+4339
-2202
lines changed

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseDialect.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.hibernate.dialect.OracleDialect;
2626
import org.hibernate.dialect.function.CommonFunctionFactory;
2727
import org.hibernate.dialect.function.OracleTruncFunction;
28+
import org.hibernate.dialect.lock.spi.OuterJoinLockingLevel;
2829
import org.hibernate.dialect.pagination.LimitHandler;
2930
import org.hibernate.dialect.sequence.SequenceSupport;
3031
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
@@ -585,9 +586,9 @@ public boolean supportsFromClauseInUpdate() {
585586
}
586587

587588
@Override
588-
public boolean supportsOuterJoinForUpdate() {
589+
public OuterJoinLockingLevel getOuterJoinLockingLevel() {
589590
// "SELECT FOR UPDATE can only be used with a single-table SELECT statement"
590-
return false;
591+
return OuterJoinLockingLevel.UNSUPPORTED;
591592
}
592593

593594
@Override

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseSqlAstTranslator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,10 @@ protected void renderTableGroupJoin(TableGroupJoin tableGroupJoin, List<TableGro
113113
predicate = tableGroupJoin.getPredicate();
114114
}
115115
if ( predicate != null && !predicate.isEmpty() ) {
116-
renderTableGroup( tableGroupJoin.getJoinedGroup(), predicate, tableGroupJoinCollector );
116+
renderJoinedTableGroup( tableGroupJoin.getJoinedGroup(), predicate, tableGroupJoinCollector );
117117
}
118118
else {
119-
renderTableGroup( tableGroupJoin.getJoinedGroup(), null, tableGroupJoinCollector );
119+
renderJoinedTableGroup( tableGroupJoin.getJoinedGroup(), null, tableGroupJoinCollector );
120120
}
121121
}
122122

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheDialect.java

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@
44
*/
55
package org.hibernate.community.dialect;
66

7-
import java.sql.CallableStatement;
8-
import java.sql.ResultSet;
9-
import java.sql.SQLException;
10-
import java.sql.Types;
11-
7+
import jakarta.persistence.GenerationType;
8+
import jakarta.persistence.TemporalType;
129
import org.hibernate.LockMode;
10+
import org.hibernate.LockOptions;
11+
import org.hibernate.Locking;
1312
import org.hibernate.boot.model.FunctionContributions;
1413
import org.hibernate.cfg.Environment;
1514
import org.hibernate.community.dialect.identity.CacheIdentityColumnSupport;
@@ -20,13 +19,9 @@
2019
import org.hibernate.dialect.function.CommonFunctionFactory;
2120
import org.hibernate.dialect.identity.IdentityColumnSupport;
2221
import org.hibernate.dialect.lock.LockingStrategy;
23-
import org.hibernate.dialect.lock.OptimisticForceIncrementLockingStrategy;
24-
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
25-
import org.hibernate.dialect.lock.PessimisticForceIncrementLockingStrategy;
2622
import org.hibernate.dialect.lock.PessimisticReadUpdateLockingStrategy;
2723
import org.hibernate.dialect.lock.PessimisticWriteUpdateLockingStrategy;
28-
import org.hibernate.dialect.lock.SelectLockingStrategy;
29-
import org.hibernate.dialect.lock.UpdateLockingStrategy;
24+
import org.hibernate.dialect.lock.spi.OuterJoinLockingLevel;
3025
import org.hibernate.dialect.pagination.LimitHandler;
3126
import org.hibernate.dialect.pagination.TopLimitHandler;
3227
import org.hibernate.dialect.sequence.SequenceSupport;
@@ -39,24 +34,29 @@
3934
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
4035
import org.hibernate.internal.util.JdbcExceptionHelper;
4136
import org.hibernate.persister.entity.EntityPersister;
42-
import org.hibernate.query.sqm.IntervalType;
4337
import org.hibernate.query.common.TemporalUnit;
38+
import org.hibernate.query.sqm.IntervalType;
4439
import org.hibernate.sql.ast.SqlAstTranslator;
4540
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
41+
import org.hibernate.sql.ast.spi.LockingClauseStrategy;
4642
import org.hibernate.sql.ast.spi.SqlAppender;
4743
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
4844
import org.hibernate.sql.ast.tree.Statement;
45+
import org.hibernate.sql.ast.tree.select.QuerySpec;
4946
import org.hibernate.sql.exec.spi.JdbcOperation;
5047
import org.hibernate.type.StandardBasicTypes;
5148
import org.hibernate.type.descriptor.jdbc.JdbcType;
5249
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
5350

54-
import jakarta.persistence.GenerationType;
55-
import jakarta.persistence.TemporalType;
51+
import java.sql.CallableStatement;
52+
import java.sql.ResultSet;
53+
import java.sql.SQLException;
54+
import java.sql.Types;
5655

5756
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
5857
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.INTEGER;
5958
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.STRING;
59+
import static org.hibernate.sql.ast.internal.NonLockingClauseStrategy.NON_CLAUSE_STRATEGY;
6060
import static org.hibernate.type.SqlTypes.BLOB;
6161
import static org.hibernate.type.SqlTypes.BOOLEAN;
6262
import static org.hibernate.type.SqlTypes.CLOB;
@@ -310,32 +310,27 @@ public String getQuerySequencesString() {
310310
// lock acquisition support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
311311

312312
@Override
313-
public boolean supportsOuterJoinForUpdate() {
314-
return false;
313+
public LockingClauseStrategy getLockingClauseStrategy(QuerySpec querySpec, LockOptions lockOptions) {
314+
return NON_CLAUSE_STRATEGY;
315315
}
316316

317317
@Override
318-
public LockingStrategy getLockingStrategy(EntityPersister lockable, LockMode lockMode) {
318+
public OuterJoinLockingLevel getOuterJoinLockingLevel() {
319+
// InterSystems Cache' does not current support "SELECT ... FOR UPDATE" syntax at all
320+
return OuterJoinLockingLevel.UNSUPPORTED;
321+
}
322+
323+
@Override
324+
protected LockingStrategy buildPessimisticWriteStrategy(EntityPersister lockable, LockMode lockMode, Locking.Scope lockScope) {
319325
// InterSystems Cache' does not current support "SELECT ... FOR UPDATE" syntax...
320326
// Set your transaction mode to READ_COMMITTED before using
321-
switch (lockMode) {
322-
case PESSIMISTIC_FORCE_INCREMENT:
323-
return new PessimisticForceIncrementLockingStrategy(lockable, lockMode);
324-
case PESSIMISTIC_WRITE:
325-
return new PessimisticWriteUpdateLockingStrategy(lockable, lockMode);
326-
case PESSIMISTIC_READ:
327-
return new PessimisticReadUpdateLockingStrategy(lockable, lockMode);
328-
case OPTIMISTIC:
329-
return new OptimisticLockingStrategy(lockable, lockMode);
330-
case OPTIMISTIC_FORCE_INCREMENT:
331-
return new OptimisticForceIncrementLockingStrategy(lockable, lockMode);
332-
}
333-
if ( lockMode.greaterThan( LockMode.READ ) ) {
334-
return new UpdateLockingStrategy( lockable, lockMode );
335-
}
336-
else {
337-
return new SelectLockingStrategy( lockable, lockMode );
338-
}
327+
return new PessimisticWriteUpdateLockingStrategy( lockable, lockMode );
328+
}
329+
330+
protected LockingStrategy buildPessimisticReadStrategy(EntityPersister lockable, LockMode lockMode, Locking.Scope lockScope) {
331+
// InterSystems Cache' does not current support "SELECT ... FOR UPDATE" syntax...
332+
// Set your transaction mode to READ_COMMITTED before using
333+
return new PessimisticReadUpdateLockingStrategy( lockable, lockMode );
339334
}
340335

341336
@Override

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheSqlAstTranslator.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import java.util.List;
88

9+
import org.hibernate.Locking;
910
import org.hibernate.engine.spi.SessionFactoryImplementor;
1011
import org.hibernate.query.sqm.ComparisonOperator;
1112
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
@@ -34,16 +35,10 @@ public CacheSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement
3435
@Override
3536
protected LockStrategy determineLockingStrategy(
3637
QuerySpec querySpec,
37-
ForUpdateClause forUpdateClause,
38-
Boolean followOnLocking) {
38+
Locking.FollowOn followOnLocking) {
3939
return LockStrategy.NONE;
4040
}
4141

42-
@Override
43-
protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) {
44-
// Cache does not support the FOR UPDATE clause
45-
}
46-
4742
@Override
4843
protected boolean needsRowsToSkip() {
4944
return true;

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.hibernate.dialect.function.PostgreSQLTruncFunction;
3535
import org.hibernate.dialect.identity.CockroachDBIdentityColumnSupport;
3636
import org.hibernate.dialect.identity.IdentityColumnSupport;
37+
import org.hibernate.dialect.lock.spi.OuterJoinLockingLevel;
3738
import org.hibernate.dialect.pagination.LimitHandler;
3839
import org.hibernate.dialect.pagination.OffsetFetchLimitHandler;
3940
import org.hibernate.dialect.sequence.PostgreSQLSequenceSupport;
@@ -92,7 +93,6 @@
9293
import java.time.temporal.TemporalAccessor;
9394
import java.util.Calendar;
9495
import java.util.Date;
95-
import java.util.Map;
9696
import java.util.TimeZone;
9797
import java.util.regex.Matcher;
9898
import java.util.regex.Pattern;
@@ -994,25 +994,10 @@ public String getForUpdateString(String aliases, LockOptions lockOptions) {
994994
if ( getVersion().isBefore( 20, 1 ) ) {
995995
return "";
996996
}
997-
/*
998-
* Parent's implementation for (aliases, lockOptions) ignores aliases.
999-
*/
1000-
if ( aliases.isEmpty() ) {
1001-
LockMode lockMode = lockOptions.getLockMode();
1002-
for ( Map.Entry<String, LockMode> entry : lockOptions.getAliasSpecificLocks() ) {
1003-
// seek the highest lock mode
1004-
if ( entry.getValue().greaterThan(lockMode) ) {
1005-
aliases = entry.getKey();
1006-
}
1007-
}
1008-
}
1009-
LockMode lockMode = lockOptions.getAliasSpecificLockMode( aliases );
1010-
if (lockMode == null ) {
1011-
lockMode = lockOptions.getLockMode();
1012-
}
997+
final LockMode lockMode = lockOptions.getLockMode();
1013998
return switch ( lockMode ) {
1014-
case PESSIMISTIC_READ -> getReadLockString( aliases, lockOptions.getTimeOut() );
1015-
case PESSIMISTIC_WRITE -> getWriteLockString( aliases, lockOptions.getTimeOut() );
999+
case PESSIMISTIC_READ -> getReadLockString( aliases, lockOptions.getTimeout() );
1000+
case PESSIMISTIC_WRITE -> getWriteLockString( aliases, lockOptions.getTimeout() );
10161001
case UPGRADE_NOWAIT, PESSIMISTIC_FORCE_INCREMENT -> getForUpdateNowaitString( aliases );
10171002
case UPGRADE_SKIPLOCKED -> getForUpdateSkipLockedString( aliases );
10181003
default -> "";
@@ -1100,8 +1085,8 @@ public String getForUpdateSkipLockedString(String aliases) {
11001085
}
11011086

11021087
@Override
1103-
public boolean supportsOuterJoinForUpdate() {
1104-
return false;
1088+
public OuterJoinLockingLevel getOuterJoinLockingLevel() {
1089+
return OuterJoinLockingLevel.UNSUPPORTED;
11051090
}
11061091

11071092
@Override

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacySqlAstTranslator.java

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
package org.hibernate.community.dialect;
66

7+
import org.hibernate.Locking;
78
import org.hibernate.engine.spi.SessionFactoryImplementor;
89
import org.hibernate.sql.ast.Clause;
910
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
@@ -129,35 +130,15 @@ protected void renderMaterializationHint(CteMaterialization materialization) {
129130
}
130131
}
131132

132-
@Override
133-
protected String getForShare(int timeoutMillis) {
134-
return " for share";
135-
}
136-
137-
@Override
138-
protected String getForUpdate() {
139-
return getDialect().getVersion().isBefore( 20, 1 ) ? "" : " for update";
140-
}
141-
142133
@Override
143134
protected LockStrategy determineLockingStrategy(
144135
QuerySpec querySpec,
145-
ForUpdateClause forUpdateClause,
146-
Boolean followOnLocking) {
136+
Locking.FollowOn followOnLocking) {
147137
// Support was added in 20.1: https://www.cockroachlabs.com/docs/v20.1/select-for-update.html
148138
if ( getDialect().getVersion().isBefore( 20, 1 ) ) {
149139
return LockStrategy.NONE;
150140
}
151-
return super.determineLockingStrategy( querySpec, forUpdateClause, followOnLocking );
152-
}
153-
154-
@Override
155-
protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) {
156-
// Support was added in 20.1: https://www.cockroachlabs.com/docs/v20.1/select-for-update.html
157-
if ( getDialect().getVersion().isBefore( 20, 1 ) ) {
158-
return;
159-
}
160-
super.renderForUpdateClause( querySpec, forUpdateClause );
141+
return super.determineLockingStrategy( querySpec, followOnLocking );
161142
}
162143

163144
protected boolean shouldEmulateFetchClause(QueryPart queryPart) {

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.hibernate.dialect.function.TrimFunction;
2828
import org.hibernate.dialect.identity.DB2IdentityColumnSupport;
2929
import org.hibernate.dialect.identity.IdentityColumnSupport;
30+
import org.hibernate.dialect.lock.spi.OuterJoinLockingLevel;
3031
import org.hibernate.dialect.pagination.DB2LimitHandler;
3132
import org.hibernate.dialect.pagination.LegacyDB2LimitHandler;
3233
import org.hibernate.dialect.pagination.LimitHandler;
@@ -810,8 +811,8 @@ public String getReadLockString(int timeout) {
810811
}
811812

812813
@Override
813-
public boolean supportsOuterJoinForUpdate() {
814-
return false;
814+
public OuterJoinLockingLevel getOuterJoinLockingLevel() {
815+
return OuterJoinLockingLevel.UNSUPPORTED;
815816
}
816817

817818
@Override

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacySqlAstTranslator.java

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ protected boolean needsRecursiveKeywordInWithClause() {
7575
}
7676

7777
@Override
78-
protected void renderTableReferenceJoins(TableGroup tableGroup, int swappedJoinIndex, boolean forceLeftJoin) {
78+
protected void renderTableReferenceJoins(TableGroup tableGroup, LockMode lockMode, int swappedJoinIndex, boolean forceLeftJoin) {
7979
// When we are in a recursive CTE, we can't render joins on DB2...
8080
// See https://modern-sql.com/feature/with-recursive/db2/error-345-state-42836
8181
if ( isInRecursiveQueryPart() ) {
@@ -102,7 +102,7 @@ protected void renderTableReferenceJoins(TableGroup tableGroup, int swappedJoinI
102102
}
103103
}
104104
else {
105-
super.renderTableReferenceJoins( tableGroup, swappedJoinIndex, forceLeftJoin );
105+
super.renderTableReferenceJoins( tableGroup, lockMode, swappedJoinIndex, forceLeftJoin );
106106
}
107107
}
108108

@@ -118,7 +118,7 @@ protected void renderTableGroupJoin(TableGroupJoin tableGroupJoin, List<TableGro
118118
}
119119
appendSql( COMMA_SEPARATOR_CHAR );
120120

121-
renderTableGroup( tableGroupJoin.getJoinedGroup(), null, tableGroupJoinCollector );
121+
renderJoinedTableGroup( tableGroupJoin.getJoinedGroup(), null, tableGroupJoinCollector );
122122
if ( tableGroupJoin.getPredicate() != null && !tableGroupJoin.getPredicate().isEmpty() ) {
123123
addAdditionalWherePredicate( tableGroupJoin.getPredicate() );
124124
}
@@ -212,21 +212,6 @@ protected void visitAnsiCaseSimpleExpression(
212212
}
213213
}
214214

215-
@Override
216-
protected String getForUpdate() {
217-
return " for read only with rs use and keep update locks";
218-
}
219-
220-
@Override
221-
protected String getForShare(int timeoutMillis) {
222-
return " for read only with rs use and keep share locks";
223-
}
224-
225-
@Override
226-
protected String getSkipLocked() {
227-
return " skip locked data";
228-
}
229-
230215
protected boolean shouldEmulateFetchClause(QueryPart queryPart) {
231216
// Check if current query part is already row numbering to avoid infinite recursion
232217
if ( getQueryPartForRowNumbering() == queryPart ) {

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyDialect.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.util.Locale;
1111

1212
import jakarta.persistence.Timeout;
13+
import org.hibernate.Locking;
1314
import org.hibernate.boot.model.FunctionContributions;
1415
import org.hibernate.boot.model.TypeContributions;
1516
import org.hibernate.dialect.DB2Dialect;
@@ -29,6 +30,7 @@
2930
import org.hibernate.dialect.identity.DB2IdentityColumnSupport;
3031
import org.hibernate.dialect.identity.IdentityColumnSupport;
3132
import org.hibernate.community.dialect.pagination.DerbyLimitHandler;
33+
import org.hibernate.dialect.lock.spi.OuterJoinLockingLevel;
3234
import org.hibernate.dialect.pagination.LimitHandler;
3335
import org.hibernate.community.dialect.sequence.DerbySequenceSupport;
3436
import org.hibernate.dialect.sequence.SequenceSupport;
@@ -62,6 +64,8 @@
6264
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
6365
import org.hibernate.sql.ast.SqlAstTranslator;
6466
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
67+
import org.hibernate.sql.ast.internal.PessimisticLockKind;
68+
import org.hibernate.sql.ast.spi.LockingClauseStrategy;
6569
import org.hibernate.sql.ast.spi.SqlAppender;
6670
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
6771
import org.hibernate.sql.ast.tree.Statement;
@@ -568,6 +572,11 @@ public boolean supportsCommentOn() {
568572
return false;
569573
}
570574

575+
@Override
576+
protected LockingClauseStrategy buildLockingClauseStrategy(PessimisticLockKind lockKind, RowLockStrategy rowLockStrategy, Locking.Scope lockScope, int timeout) {
577+
return new DerbyLockingClauseStrategy( this, lockKind, rowLockStrategy, lockScope, timeout );
578+
}
579+
571580
@Override
572581
public RowLockStrategy getReadRowLockStrategy() {
573582
return RowLockStrategy.NONE;
@@ -599,9 +608,9 @@ public String getReadLockString(int timeout) {
599608
}
600609

601610
@Override
602-
public boolean supportsOuterJoinForUpdate() {
611+
public OuterJoinLockingLevel getOuterJoinLockingLevel() {
603612
//TODO: check this!
604-
return false;
613+
return OuterJoinLockingLevel.UNSUPPORTED;
605614
}
606615

607616
@Override

0 commit comments

Comments
 (0)