@@ -41,6 +41,16 @@ public class StandardLockingClauseStrategy implements LockingClauseStrategy {
41
41
private final Locking .Scope lockingScope ;
42
42
private final int timeout ;
43
43
44
+ /**
45
+ * @implNote Tracked separately from {@linkplain #rootsToLock} and
46
+ * {@linkplain #joinsToLock} to help answer {@linkplain #containsOuterJoins()}
47
+ * for {@linkplain RowLockStrategy#NONE cases} where we otherwise don't need to
48
+ * track the tables, allowing to avoid the overhead of the Sets. There is a
49
+ * slight trade-off in that we need to inspect the from-elements to make that
50
+ * determination when we might otherwise not need to - memory versus cpu.
51
+ */
52
+ private boolean queryHasOuterJoins = false ;
53
+
44
54
private Set <TableGroup > rootsToLock ;
45
55
private Set <TableGroupJoin > joinsToLock ;
46
56
@@ -61,10 +71,21 @@ public StandardLockingClauseStrategy(
61
71
62
72
@ Override
63
73
public void registerRoot (TableGroup root ) {
64
- if ( rootsToLock == null ) {
65
- rootsToLock = new HashSet <>();
74
+ if ( !queryHasOuterJoins && !dialect .supportsOuterJoinForUpdate () ) {
75
+ if ( root .getModelPart () instanceof EntityPersister entityMapping ) {
76
+ if ( entityMapping .hasMultipleTables () ) {
77
+ // joined inheritance and/or secondary tables - inherently has outer joins
78
+ queryHasOuterJoins = true ;
79
+ }
80
+ }
81
+ }
82
+
83
+ if ( rowLockStrategy != RowLockStrategy .NONE ) {
84
+ if ( rootsToLock == null ) {
85
+ rootsToLock = new HashSet <>();
86
+ }
87
+ rootsToLock .add ( root );
66
88
}
67
- rootsToLock .add ( root );
68
89
}
69
90
70
91
@ Override
@@ -90,41 +111,32 @@ else if ( lockingScope == Locking.Scope.INCLUDE_FETCHES ) {
90
111
}
91
112
92
113
private void trackJoin (TableGroupJoin join ) {
93
- if ( joinsToLock == null ) {
94
- joinsToLock = new LinkedHashSet <>();
95
- }
96
- joinsToLock .add ( join );
97
- }
98
-
99
- @ Override
100
- public boolean containsOuterJoins () {
101
- for ( TableGroup tableGroup : rootsToLock ) {
102
- if ( tableGroup .getModelPart () instanceof EntityPersister entityMapping ) {
114
+ if ( !queryHasOuterJoins && !dialect .supportsOuterJoinForUpdate () ) {
115
+ final TableGroup joinedGroup = join .getJoinedGroup ();
116
+ if ( join .isInitialized ()
117
+ && join .getJoinType () != SqlAstJoinType .INNER
118
+ && !joinedGroup .isVirtual () ) {
119
+ queryHasOuterJoins = true ;
120
+ }
121
+ else if ( joinedGroup .getModelPart () instanceof EntityPersister entityMapping ) {
103
122
if ( entityMapping .hasMultipleTables () ) {
104
123
// joined inheritance and/or secondary tables - inherently has outer joins
105
- return true ;
124
+ queryHasOuterJoins = true ;
106
125
}
107
126
}
108
127
}
109
128
110
- if ( joinsToLock != null ) {
111
- for ( TableGroupJoin tableGroupJoin : joinsToLock ) {
112
- final TableGroup joinedGroup = tableGroupJoin .getJoinedGroup ();
113
- if ( tableGroupJoin .isInitialized ()
114
- && tableGroupJoin .getJoinType () != SqlAstJoinType .INNER
115
- && !joinedGroup .isVirtual () ) {
116
- return true ;
117
- }
118
- if ( joinedGroup .getModelPart () instanceof EntityPersister entityMapping ) {
119
- if ( entityMapping .hasMultipleTables () ) {
120
- // joined inheritance and/or secondary tables - inherently has outer joins
121
- return true ;
122
- }
123
- }
129
+ if ( rowLockStrategy != RowLockStrategy .NONE ) {
130
+ if ( joinsToLock == null ) {
131
+ joinsToLock = new LinkedHashSet <>();
124
132
}
133
+ joinsToLock .add ( join );
125
134
}
135
+ }
126
136
127
- return false ;
137
+ @ Override
138
+ public boolean containsOuterJoins () {
139
+ return queryHasOuterJoins ;
128
140
}
129
141
130
142
@ Override
0 commit comments