Skip to content

Commit b6560ed

Browse files
committed
HHH-19336 - Proper implementation for JPA extended locking scope
HHH-19459 - LockScope, FollowOnLocking
1 parent 69fd7b8 commit b6560ed

File tree

5 files changed

+70
-9
lines changed

5 files changed

+70
-9
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1383,7 +1383,7 @@ public boolean supportsSkipLocked() {
13831383

13841384
@Override
13851385
public RowLockStrategy getWriteRowLockStrategy() {
1386-
return RowLockStrategy.COLUMN;
1386+
return RowLockStrategy.COLUMN_NAME;
13871387
}
13881388

13891389
@Override

hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1437,7 +1437,7 @@ public boolean supportsSkipLocked() {
14371437

14381438
@Override
14391439
public RowLockStrategy getWriteRowLockStrategy() {
1440-
return RowLockStrategy.COLUMN;
1440+
return RowLockStrategy.COLUMN_NAME;
14411441
}
14421442

14431443
@Override

hibernate-core/src/main/java/org/hibernate/dialect/RowLockStrategy.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,19 @@
88
* The strategy for rendering which row to lock with the {@code FOR UPDATE OF} clause.
99
*
1010
* @author Christian Beikov
11+
* @author Steve Ebersole
1112
*/
1213
public enum RowLockStrategy {
1314
/**
14-
* Use a column name.
15+
* Use the column reference (column name qualified by the table alias).
1516
*/
1617
COLUMN,
1718
/**
18-
* Use a table alias.
19+
* Use the column name.
20+
*/
21+
COLUMN_NAME,
22+
/**
23+
* Use the table alias.
1924
*/
2025
TABLE,
2126
/**

hibernate-core/src/main/java/org/hibernate/sql/ast/internal/StandardForUpdateClauseStrategy.java

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
package org.hibernate.sql.ast.internal;
66

7+
import org.hibernate.HibernateException;
78
import org.hibernate.LockMode;
89
import org.hibernate.LockOptions;
910
import org.hibernate.Locking;
@@ -146,7 +147,7 @@ protected void renderRowLocking(RowLockStrategy rowLockStrategy, Set<TableGroup>
146147
}
147148

148149
protected void renderResultSetOptions(Dialect dialect, SqlAppender sqlAppender) {
149-
// todo : hook for derby
150+
// hook for Derby
150151
}
151152

152153
protected void renderLockedRowHandling(int timeout, SqlAppender sqlAppender) {
@@ -175,10 +176,9 @@ private void collectLockItems(TableGroup tableGroup, List<String> lockItems) {
175176
else if ( rowLockStrategy == RowLockStrategy.COLUMN ) {
176177
addColumnRefs( tableGroup, lockItems );
177178
}
178-
}
179-
180-
private void addColumnRefs(TableGroup tableGroup, List<String> lockItems) {
181-
Collections.addAll( lockItems, determineKeyColumnRefs( tableGroup ) );
179+
else if ( rowLockStrategy == RowLockStrategy.COLUMN_NAME ) {
180+
addColumnNames( tableGroup, lockItems );
181+
}
182182
}
183183

184184
private void addTableAliases(TableGroup tableGroup, List<String> lockItems) {
@@ -193,6 +193,10 @@ private void addTableAliases(TableGroup tableGroup, List<String> lockItems) {
193193
}
194194
}
195195

196+
private void addColumnRefs(TableGroup tableGroup, List<String> lockItems) {
197+
Collections.addAll( lockItems, determineKeyColumnRefs( tableGroup ) );
198+
}
199+
196200
private String[] determineKeyColumnRefs(TableGroup tableGroup) {
197201
final String[] result = determineKeyColumnNames( tableGroup.getModelPart() );
198202
final String tableAlias = tableGroup.getPrimaryTableReference().getIdentificationVariable();
@@ -207,6 +211,8 @@ private String[] determineKeyColumnNames(ModelPart modelPart) {
207211
return entityPersister.getIdentifierColumnNames();
208212
}
209213
else if ( modelPart instanceof PluralAttributeMapping pluralAttributeMapping ) {
214+
// todo : seems like this ought to return the column name(s)
215+
// to then be qualified with the table alias
210216
return pluralAttributeMapping.getCollectionDescriptor().getKeyColumnAliases( null );
211217
}
212218
else if ( modelPart instanceof EntityAssociationMapping entityAssociationMapping ) {
@@ -217,6 +223,33 @@ else if ( modelPart instanceof EntityAssociationMapping entityAssociationMapping
217223
}
218224
}
219225

226+
private void addColumnNames(TableGroup tableGroup, List<String> lockItems) {
227+
final ModelPart keyColumnPart = determineKeyPart( tableGroup.getModelPart() );
228+
if ( keyColumnPart == null ) {
229+
throw new HibernateException( "Could not determine ModelPart defining key columns - " + tableGroup.getModelPart() );
230+
}
231+
keyColumnPart.forEachSelectable( (selectionIndex, selectableMapping) -> {
232+
if ( !selectableMapping.isFormula() ) {
233+
lockItems.add( selectableMapping.getSelectableName() );
234+
}
235+
} );
236+
}
237+
238+
private ModelPart determineKeyPart(ModelPart modelPart) {
239+
if ( modelPart instanceof EntityPersister entityPersister ) {
240+
return entityPersister.getIdentifierMapping();
241+
}
242+
else if ( modelPart instanceof PluralAttributeMapping pluralAttributeMapping ) {
243+
return pluralAttributeMapping.getKeyDescriptor();
244+
}
245+
else if ( modelPart instanceof EntityAssociationMapping entityAssociationMapping ) {
246+
return entityAssociationMapping.getForeignKeyDescriptor();
247+
}
248+
else {
249+
return null;
250+
}
251+
}
252+
220253
public static ForUpdateClauseStrategy strategy(Dialect dialect, QuerySpec querySpec, LockOptions lockOptions) {
221254
return strategy(
222255
dialect,

hibernate-core/src/test/java/org/hibernate/orm/test/locking/scope/Helper.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ public String getTableAlias() {
8484
};
8585
}
8686

87+
public String[] getKeyColumnNames() {
88+
return switch ( this ) {
89+
case BOOKS -> new String[] {"id"};
90+
case BOOK_TAGS -> new String[] {"book_fk"};
91+
case BOOK_AUTHORS -> new String[] {"book_fk"};
92+
case PUBLISHER -> new String[] {"id"};
93+
};
94+
}
95+
8796
public String[] getKeyColumnAliases() {
8897
return switch ( this ) {
8998
case BOOKS -> new String[] {"b1_0.id"};
@@ -116,6 +125,20 @@ else if ( rowLockStrategy == RowLockStrategy.TABLE ) {
116125
}
117126
aliases = buffer.toString();
118127
}
128+
else if ( rowLockStrategy == RowLockStrategy.COLUMN_NAME ) {
129+
final StringBuilder buffer = new StringBuilder();
130+
boolean firstPass = true;
131+
for ( Table table : tablesFetched ) {
132+
if ( firstPass ) {
133+
firstPass = false;
134+
}
135+
else {
136+
buffer.append( "," );
137+
}
138+
buffer.append( StringHelper.join( ",", table.getKeyColumnNames() ) );
139+
}
140+
aliases = buffer.toString();
141+
}
119142
else {
120143
final StringBuilder buffer = new StringBuilder();
121144
boolean firstPass = true;

0 commit comments

Comments
 (0)