21
21
import java .util .List ;
22
22
import java .util .Map ;
23
23
import java .util .Set ;
24
+ import java .util .concurrent .ConcurrentHashMap ;
24
25
25
26
import org .hibernate .AssertionFailure ;
26
27
import org .hibernate .EntityMode ;
@@ -236,7 +237,9 @@ public abstract class AbstractEntityPersister
236
237
237
238
private final Map uniqueKeyLoaders = new HashMap ();
238
239
private final Map lockers = new HashMap ();
239
- private final Map loaders = new HashMap ();
240
+ private UniqueEntityLoader noneLockLoader ;
241
+ private UniqueEntityLoader readLockLoader ;
242
+ private final Map <Object , UniqueEntityLoader > loaders = new ConcurrentHashMap <>();
240
243
241
244
// SQL strings
242
245
private String sqlVersionSelectString ;
@@ -4117,61 +4120,14 @@ protected Map getLoaders() {
4117
4120
4118
4121
//Relational based Persisters should be content with this implementation
4119
4122
protected void createLoaders () {
4120
- final Map loaders = getLoaders ();
4121
- loaders .put ( LockMode .NONE , createEntityLoader ( LockMode .NONE ) );
4123
+ // We load the entity loaders for the most common lock modes.
4122
4124
4123
- UniqueEntityLoader readLoader = createEntityLoader ( LockMode .READ );
4124
- loaders . put ( LockMode .READ , readLoader );
4125
+ noneLockLoader = createEntityLoader ( LockMode .NONE );
4126
+ readLockLoader = createEntityLoader ( LockMode .READ );
4125
4127
4126
- //TODO: inexact, what we really need to know is: are any outer joins used?
4127
- boolean disableForUpdate = getSubclassTableSpan () > 1 &&
4128
- hasSubclasses () &&
4129
- !getFactory ().getDialect ().supportsOuterJoinForUpdate ();
4128
+ final Map loaders = getLoaders ();
4130
4129
4131
- loaders .put (
4132
- LockMode .UPGRADE ,
4133
- disableForUpdate ?
4134
- readLoader :
4135
- createEntityLoader ( LockMode .UPGRADE )
4136
- );
4137
- loaders .put (
4138
- LockMode .UPGRADE_NOWAIT ,
4139
- disableForUpdate ?
4140
- readLoader :
4141
- createEntityLoader ( LockMode .UPGRADE_NOWAIT )
4142
- );
4143
- loaders .put (
4144
- LockMode .UPGRADE_SKIPLOCKED ,
4145
- disableForUpdate ?
4146
- readLoader :
4147
- createEntityLoader ( LockMode .UPGRADE_SKIPLOCKED )
4148
- );
4149
- loaders .put (
4150
- LockMode .FORCE ,
4151
- disableForUpdate ?
4152
- readLoader :
4153
- createEntityLoader ( LockMode .FORCE )
4154
- );
4155
- loaders .put (
4156
- LockMode .PESSIMISTIC_READ ,
4157
- disableForUpdate ?
4158
- readLoader :
4159
- createEntityLoader ( LockMode .PESSIMISTIC_READ )
4160
- );
4161
- loaders .put (
4162
- LockMode .PESSIMISTIC_WRITE ,
4163
- disableForUpdate ?
4164
- readLoader :
4165
- createEntityLoader ( LockMode .PESSIMISTIC_WRITE )
4166
- );
4167
- loaders .put (
4168
- LockMode .PESSIMISTIC_FORCE_INCREMENT ,
4169
- disableForUpdate ?
4170
- readLoader :
4171
- createEntityLoader ( LockMode .PESSIMISTIC_FORCE_INCREMENT )
4172
- );
4173
- loaders .put ( LockMode .OPTIMISTIC , createEntityLoader ( LockMode .OPTIMISTIC ) );
4174
- loaders .put ( LockMode .OPTIMISTIC_FORCE_INCREMENT , createEntityLoader ( LockMode .OPTIMISTIC_FORCE_INCREMENT ) );
4130
+ // The loaders for the other lock modes are lazily loaded and will later be stored in this map.
4175
4131
4176
4132
loaders .put (
4177
4133
"merge" ,
@@ -4183,6 +4139,46 @@ protected void createLoaders() {
4183
4139
);
4184
4140
}
4185
4141
4142
+ private UniqueEntityLoader getLoaderByLockMode (LockMode lockMode ) {
4143
+ if ( LockMode .NONE == lockMode ) {
4144
+ return noneLockLoader ;
4145
+ }
4146
+ else if ( LockMode .READ == lockMode ) {
4147
+ return readLockLoader ;
4148
+ }
4149
+
4150
+ return loaders .computeIfAbsent ( lockMode , this ::createLazyLoadedEntityLoader );
4151
+ }
4152
+
4153
+ private UniqueEntityLoader createLazyLoadedEntityLoader (Object lockModeObject ) {
4154
+ // Unfortunately, the loaders map mixes LockModes and Strings as keys so we need to accept an Object.
4155
+ // The cast is safe as we will always call this method with a LockMode.
4156
+ LockMode lockMode = (LockMode ) lockModeObject ;
4157
+
4158
+ switch ( lockMode ) {
4159
+ case NONE :
4160
+ case READ :
4161
+ case OPTIMISTIC :
4162
+ case OPTIMISTIC_FORCE_INCREMENT :
4163
+ return createEntityLoader ( lockMode );
4164
+ case UPGRADE :
4165
+ case UPGRADE_NOWAIT :
4166
+ case UPGRADE_SKIPLOCKED :
4167
+ case FORCE :
4168
+ case PESSIMISTIC_READ :
4169
+ case PESSIMISTIC_WRITE :
4170
+ case PESSIMISTIC_FORCE_INCREMENT :
4171
+ //TODO: inexact, what we really need to know is: are any outer joins used?
4172
+ boolean disableForUpdate = getSubclassTableSpan () > 1 &&
4173
+ hasSubclasses () &&
4174
+ !getFactory ().getDialect ().supportsOuterJoinForUpdate ();
4175
+
4176
+ return disableForUpdate ? readLockLoader : createEntityLoader ( lockMode );
4177
+ default :
4178
+ throw new IllegalStateException ( String .format ( "Lock mode %1$s not supported by entity loaders." , lockMode ) );
4179
+ }
4180
+ }
4181
+
4186
4182
protected void createQueryLoader () {
4187
4183
if ( loaderName != null ) {
4188
4184
queryLoader = new NamedQueryLoader ( loaderName , this );
@@ -4276,7 +4272,7 @@ else if ( lockOptions.getTimeOut() != LockOptions.WAIT_FOREVER ) {
4276
4272
return createEntityLoader ( lockOptions , session .getLoadQueryInfluencers () );
4277
4273
}
4278
4274
else {
4279
- return (UniqueEntityLoader ) getLoaders (). get ( lockOptions .getLockMode () );
4275
+ return (UniqueEntityLoader ) getLoaderByLockMode ( lockOptions .getLockMode () );
4280
4276
}
4281
4277
}
4282
4278
0 commit comments