diff --git a/hibernate-core/src/main/java/org/hibernate/LockMode.java b/hibernate-core/src/main/java/org/hibernate/LockMode.java index cd200d9b5b..31a68fb5a7 100644 --- a/hibernate-core/src/main/java/org/hibernate/LockMode.java +++ b/hibernate-core/src/main/java/org/hibernate/LockMode.java @@ -208,4 +208,37 @@ public enum LockMode { throw new IllegalArgumentException( "Unable to interpret LockMode reference from incoming external form : " + externalForm ); } + + /** + * @return an instance of {@link LockOptions} with this lock mode, and + * all other settings defaulted. + */ + public LockOptions toLockOptions() { + // we have to do this in a big switch to + // avoid circularities in the constructor + switch (this) { + case NONE: + return LockOptions.NONE; + case READ: + return LockOptions.READ; + case OPTIMISTIC: + return LockOptions.OPTIMISTIC; + case OPTIMISTIC_FORCE_INCREMENT: + return LockOptions.OPTIMISTIC_FORCE_INCREMENT; + case UPGRADE_NOWAIT: + return LockOptions.UPGRADE_NOWAIT; + case UPGRADE_SKIPLOCKED: + return LockOptions.UPGRADE_SKIPLOCKED; + case PESSIMISTIC_READ: + return LockOptions.PESSIMISTIC_READ; + case PESSIMISTIC_WRITE: + return LockOptions.PESSIMISTIC_WRITE; + case PESSIMISTIC_FORCE_INCREMENT: + return LockOptions.PESSIMISTIC_FORCE_INCREMENT; + case WRITE: + throw new UnsupportedOperationException("WRITE is not a valid LockMode as an argument"); + default: + throw new IllegalStateException( "Unexpected value: " + this ); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/LockOptions.java b/hibernate-core/src/main/java/org/hibernate/LockOptions.java index 14bea997e1..210f8c7f7f 100644 --- a/hibernate-core/src/main/java/org/hibernate/LockOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/LockOptions.java @@ -55,13 +55,49 @@ public class LockOptions implements Serializable { * Represents {@link LockMode#NONE}, to which timeout and scope are * not applicable. */ - public static final LockOptions NONE = new LockOptions(true, LockMode.NONE); + public static final LockOptions NONE = new LockOptions( true, LockMode.NONE ); /** * Represents {@link LockMode#READ}, to which timeout and scope are * not applicable. */ - public static final LockOptions READ = new LockOptions(true, LockMode.READ); + public static final LockOptions READ = new LockOptions( true, LockMode.READ ); + + /** + * Represents {@link LockMode#OPTIMISTIC}. + */ + static final LockOptions OPTIMISTIC = new LockOptions( true, LockMode.OPTIMISTIC ); + + /** + * Represents {@link LockMode#OPTIMISTIC_FORCE_INCREMENT}, to which + * timeout and scope are not applicable. + */ + static final LockOptions OPTIMISTIC_FORCE_INCREMENT = new LockOptions( true, LockMode.OPTIMISTIC_FORCE_INCREMENT ); + + /** + * Represents {@link LockMode#PESSIMISTIC_READ}. + */ + static final LockOptions PESSIMISTIC_READ = new LockOptions( true, LockMode.PESSIMISTIC_READ ); + + /** + * Represents {@link LockMode#PESSIMISTIC_WRITE}. + */ + static final LockOptions PESSIMISTIC_WRITE = new LockOptions( true, LockMode.PESSIMISTIC_WRITE ); + + /** + * Represents {@link LockMode#PESSIMISTIC_FORCE_INCREMENT}. + */ + static final LockOptions PESSIMISTIC_FORCE_INCREMENT = new LockOptions( true, LockMode.PESSIMISTIC_FORCE_INCREMENT ); + + /** + * Represents {@link LockMode#UPGRADE_NOWAIT}. + */ + static final LockOptions UPGRADE_NOWAIT = new LockOptions( true, LockMode.UPGRADE_NOWAIT ); + + /** + * Represents {@link LockMode#UPGRADE_SKIPLOCKED}. + */ + static final LockOptions UPGRADE_SKIPLOCKED = new LockOptions( true, LockMode.UPGRADE_SKIPLOCKED ); /** * Represents {@link LockMode#PESSIMISTIC_WRITE} with @@ -69,7 +105,7 @@ public class LockOptions implements Serializable { * {@linkplain PessimisticLockScope#NORMAL no extension of the * lock to owned collections}. */ - public static final LockOptions UPGRADE = new LockOptions(true, LockMode.PESSIMISTIC_WRITE); + public static final LockOptions UPGRADE = PESSIMISTIC_WRITE; /** * Indicates that the database should not wait at all to acquire diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/CascadingActions.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/CascadingActions.java index 8c8c3ec3be..5c6e9ce983 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/CascadingActions.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/CascadingActions.java @@ -92,18 +92,7 @@ public class CascadingActions { LockOptions lockOptions, boolean isCascadeDeleteEnabled) { LOG.tracev( "Cascading to lock: {0}", entityName ); - LockMode lockMode = LockMode.NONE; - LockOptions lr = new LockOptions(); - if ( lockOptions != null ) { - lr.setTimeOut( lockOptions.getTimeOut() ); - lr.setScope( lockOptions.getScope() ); - lr.setFollowOnLocking( lockOptions.getFollowOnLocking() ); - if ( lockOptions.getScope() ) { - lockMode = lockOptions.getLockMode(); - } - } - lr.setLockMode( lockMode ); - session.buildLockRequest( lr ).lock( entityName, child ); + session.lock( entityName, child, lockOptions ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java index ef0f40e5bd..2e8d71ef4f 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java @@ -189,7 +189,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener { if ( currentLockMode.greaterThan( requestedLockMode ) ) { // the requested lock-mode is less restrictive than the current one // - pass along the current lock-mode (after accounting for WRITE) - lockOptionsToUse = LockOptions.copy( event.getLockOptions(), new LockOptions() ); + lockOptionsToUse = event.getLockOptions().makeCopy(); if ( currentLockMode == LockMode.WRITE || currentLockMode == LockMode.PESSIMISTIC_WRITE || currentLockMode == LockMode.PESSIMISTIC_READ ) { diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/LoadEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/LoadEvent.java index eba87da4fb..da4ce3544a 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/spi/LoadEvent.java +++ b/hibernate-core/src/main/java/org/hibernate/event/spi/LoadEvent.java @@ -6,7 +6,6 @@ */ package org.hibernate.event.spi; -import org.hibernate.AssertionFailure; import org.hibernate.LockMode; import org.hibernate.LockOptions; @@ -16,38 +15,20 @@ import org.hibernate.LockOptions; * @author Steve Ebersole */ public class LoadEvent extends AbstractEvent { - public static final LockMode DEFAULT_LOCK_MODE = LockMode.NONE; - //Performance hotspot: avoid allocating unneeded LockOptions - public static final LockOptions DEFAULT_LOCK_OPTIONS = new LockOptions() { - @Override - public LockOptions setLockMode(LockMode lockMode) { - throw new AssertionFailure( "Should not be invoked: DEFAULT_LOCK_OPTIONS needs to be treated as immutable." ); - } - @Override - public LockOptions setAliasSpecificLockMode(String alias, LockMode lockMode) { - throw new AssertionFailure( "Should not be invoked: DEFAULT_LOCK_OPTIONS needs to be treated as immutable." ); - } - @Override - public LockOptions setTimeOut(int timeout) { - throw new AssertionFailure( "Should not be invoked: DEFAULT_LOCK_OPTIONS needs to be treated as immutable." ); - } - @Override - public LockOptions setScope(boolean scope) { - throw new AssertionFailure( "Should not be invoked: DEFAULT_LOCK_OPTIONS needs to be treated as immutable." ); - } - }; +// public static final LockMode DEFAULT_LOCK_MODE = LockMode.NONE; +// public static final LockOptions DEFAULT_LOCK_OPTIONS = DEFAULT_LOCK_MODE.toLockOptions(); private Object entityId; private String entityClassName; private Object instanceToLoad; - private LockOptions lockOptions; + private final LockOptions lockOptions; private final boolean isAssociationFetch; private Object result; private PostLoadEvent postLoadEvent; private Boolean readOnly; public LoadEvent(Object entityId, Object instanceToLoad, EventSource source, Boolean readOnly) { - this( entityId, null, instanceToLoad, DEFAULT_LOCK_OPTIONS, false, source, readOnly ); + this( entityId, null, instanceToLoad, LockMode.NONE.toLockOptions(), false, source, readOnly ); } public LoadEvent(Object entityId, String entityClassName, LockMode lockMode, EventSource source, Boolean readOnly) { @@ -59,7 +40,7 @@ public class LoadEvent extends AbstractEvent { } public LoadEvent(Object entityId, String entityClassName, boolean isAssociationFetch, EventSource source, Boolean readOnly) { - this( entityId, entityClassName, null, DEFAULT_LOCK_OPTIONS, isAssociationFetch, source, readOnly ); + this( entityId, entityClassName, null, LockMode.NONE.toLockOptions(), isAssociationFetch, source, readOnly ); } private LoadEvent( @@ -74,7 +55,7 @@ public class LoadEvent extends AbstractEvent { entityId, entityClassName, instanceToLoad, - lockMode == DEFAULT_LOCK_MODE ? DEFAULT_LOCK_OPTIONS : new LockOptions().setLockMode( lockMode ), + lockMode.toLockOptions(), isAssociationFetch, source, readOnly @@ -100,7 +81,7 @@ public class LoadEvent extends AbstractEvent { throw new IllegalArgumentException("Invalid lock mode for loading"); } else if ( lockOptions.getLockMode() == null ) { - lockOptions.setLockMode(DEFAULT_LOCK_MODE); + lockOptions.setLockMode( LockMode.NONE ); } this.entityId = entityId; @@ -148,37 +129,10 @@ public class LoadEvent extends AbstractEvent { return lockOptions.getLockMode(); } - public void setLockMode(LockMode lockMode) { - if ( lockMode != lockOptions.getLockMode() ) { - writingOnLockOptions(); - this.lockOptions.setLockMode( lockMode ); - } - } - - private void writingOnLockOptions() { - if ( lockOptions == DEFAULT_LOCK_OPTIONS ) { - this.lockOptions = new LockOptions(); - } - } - - public void setLockTimeout(int timeout) { - if ( timeout != lockOptions.getTimeOut() ) { - writingOnLockOptions(); - this.lockOptions.setTimeOut( timeout ); - } - } - public int getLockTimeout() { return this.lockOptions.getTimeOut(); } - public void setLockScope(boolean cascade) { - if ( lockOptions.getScope() != cascade ) { - writingOnLockOptions(); - this.lockOptions.setScope( cascade ); - } - } - public boolean getLockScope() { return this.lockOptions.getScope(); } diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/LockEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/LockEvent.java index 05ef976a2f..367bc2f7ab 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/spi/LockEvent.java +++ b/hibernate-core/src/main/java/org/hibernate/event/spi/LockEvent.java @@ -33,7 +33,7 @@ public class LockEvent extends AbstractEvent { public LockEvent(Object object, LockMode lockMode, EventSource source) { super(source); this.object = object; - this.lockOptions = new LockOptions().setLockMode(lockMode); + this.lockOptions = lockMode.toLockOptions(); } public LockEvent(Object object, LockOptions lockOptions, EventSource source) { @@ -58,24 +58,12 @@ public class LockEvent extends AbstractEvent { return lockOptions.getLockMode(); } - public void setLockMode(LockMode lockMode) { - this.lockOptions.setLockMode(lockMode); - } - - public void setLockTimeout(int timeout) { - this.lockOptions.setTimeOut(timeout); - } - public int getLockTimeout() { - return this.lockOptions.getTimeOut(); - } - - public void setLockScope(boolean cascade) { - this.lockOptions.setScope(cascade); + return lockOptions.getTimeOut(); } public boolean getLockScope() { - return this.lockOptions.getScope(); + return lockOptions.getScope(); } public String getEntityName() { diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/ResolveNaturalIdEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/ResolveNaturalIdEvent.java index 66d280494e..f3dda94c23 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/spi/ResolveNaturalIdEvent.java +++ b/hibernate-core/src/main/java/org/hibernate/event/spi/ResolveNaturalIdEvent.java @@ -31,7 +31,7 @@ public class ResolveNaturalIdEvent extends AbstractEvent { private Object entityId; public ResolveNaturalIdEvent(Map naturalIdValues, EntityPersister entityPersister, EventSource source) { - this( naturalIdValues, entityPersister, new LockOptions(), source ); + this( naturalIdValues, entityPersister, LockOptions.NONE, source ); } public ResolveNaturalIdEvent( diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 66dc5d04d8..6c1af42f07 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -991,29 +991,7 @@ public class SessionImpl @Override public void load(Object object, Object id) throws HibernateException { - LoadEvent event = loadEvent; - loadEvent = null; - if ( event == null ) { - event = new LoadEvent( id, object, this, getReadOnlyFromLoadQueryInfluencers() ); - } - else { - event.setEntityClassName( null ); - event.setEntityId( id ); - event.setInstanceToLoad( object ); - event.setLockMode( LoadEvent.DEFAULT_LOCK_MODE ); - event.setLockScope( LoadEvent.DEFAULT_LOCK_OPTIONS.getScope() ); - event.setLockTimeout( LoadEvent.DEFAULT_LOCK_OPTIONS.getTimeOut() ); - } - - fireLoad( event, LoadEventListener.RELOAD ); - - if ( loadEvent == null ) { - event.setEntityClassName( null ); - event.setEntityId( null ); - event.setInstanceToLoad( null ); - event.setResult( null ); - loadEvent = event; - } + fireLoad( new LoadEvent( id, object, this, getReadOnlyFromLoadQueryInfluencers() ), LoadEventListener.RELOAD ); } @Override @Deprecated @@ -1054,13 +1032,7 @@ public class SessionImpl event = recycleEventInstance( event, id, entityName ); fireLoadNoChecks( event, LoadEventListener.IMMEDIATE_LOAD ); Object result = event.getResult(); - if ( loadEvent == null ) { - event.setEntityClassName( null ); - event.setEntityId( null ); - event.setInstanceToLoad( null ); - event.setResult( null ); - loadEvent = event; - } + finishWithEventInstance( event ); if ( result instanceof HibernateProxy ) { return ( (HibernateProxy) result ).getHibernateLazyInitializer().getImplementation(); } @@ -1073,6 +1045,7 @@ public class SessionImpl Object id, boolean eager, boolean nullable) { + final LoadType type = internalLoadType( eager, nullable ); final EffectiveEntityGraph effectiveEntityGraph = getLoadQueryInfluencers().getEffectiveEntityGraph(); final GraphSemantic semantic = effectiveEntityGraph.getSemantic(); final RootGraphImplementor graph = effectiveEntityGraph.getGraph(); @@ -1084,38 +1057,16 @@ public class SessionImpl effectiveEntityGraph.clear(); } } - try { - final LoadType type; - if ( nullable ) { - type = LoadEventListener.INTERNAL_LOAD_NULLABLE; - } - else { - type = eager - ? LoadEventListener.INTERNAL_LOAD_EAGER - : LoadEventListener.INTERNAL_LOAD_LAZY; - } - LoadEvent event = loadEvent; loadEvent = null; - event = recycleEventInstance( event, id, entityName ); - fireLoadNoChecks( event, type ); - Object result = event.getResult(); - if ( !nullable ) { UnresolvableObjectException.throwIfNull( result, id, entityName ); } - - if ( loadEvent == null ) { - event.setEntityClassName( null ); - event.setEntityId( null ); - event.setInstanceToLoad( null ); - event.setResult( null ); - loadEvent = event; - } + finishWithEventInstance( event ); return result; } finally { @@ -1125,6 +1076,17 @@ public class SessionImpl } } + private static LoadType internalLoadType(boolean eager, boolean nullable) { + if ( nullable ) { + return LoadEventListener.INTERNAL_LOAD_NULLABLE; + } + else { + return eager + ? LoadEventListener.INTERNAL_LOAD_EAGER + : LoadEventListener.INTERNAL_LOAD_LAZY; + } + } + /** * Helper to avoid creating many new instances of LoadEvent: it's an allocation hot spot. */ @@ -1136,13 +1098,20 @@ public class SessionImpl event.setEntityClassName( entityName ); event.setEntityId( id ); event.setInstanceToLoad( null ); - event.setLockMode( LoadEvent.DEFAULT_LOCK_MODE ); - event.setLockScope( LoadEvent.DEFAULT_LOCK_OPTIONS.getScope() ); - event.setLockTimeout( LoadEvent.DEFAULT_LOCK_OPTIONS.getTimeOut() ); return event; } } + private void finishWithEventInstance(LoadEvent event) { + if ( loadEvent == null ) { + event.setEntityClassName( null ); + event.setEntityId( null ); + event.setInstanceToLoad( null ); + event.setResult( null ); + loadEvent = event; + } + } + @Override @Deprecated public T load(Class entityClass, Object id, LockMode lockMode) throws HibernateException { return this.byId( entityClass ).with( new LockOptions( lockMode ) ).getReference( id ); @@ -2123,9 +2092,9 @@ public class SessionImpl private class LockRequestImpl implements LockRequest { private final LockOptions lockOptions; - private LockRequestImpl(LockOptions lo) { - lockOptions = new LockOptions(); - LockOptions.copy( lo, lockOptions ); + private LockRequestImpl(LockOptions lockOptions) { + this.lockOptions = new LockOptions(); + LockOptions.copy( lockOptions, this.lockOptions ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index ceef38f99c..1df0a9bcab 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -4356,7 +4356,7 @@ public abstract class AbstractEntityPersister */ @Override public Object load(Object id, Object optionalObject, LockMode lockMode, SharedSessionContractImplementor session) { - return load( id, optionalObject, new LockOptions().setLockMode( lockMode ), session ); + return load( id, optionalObject, lockMode.toLockOptions(), session ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java index f9eb1082e1..2f9dc224e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java @@ -309,8 +309,8 @@ public abstract class AbstractQuery } if ( getLockOptions().getScope() ) { - hints.put( HINT_SPEC_LOCK_SCOPE, getLockOptions().getScope() ); - hints.put( HINT_JAVAEE_LOCK_SCOPE, getLockOptions().getScope() ); + hints.put( HINT_SPEC_LOCK_SCOPE, getLockOptions().getLockScope() ); + hints.put( HINT_JAVAEE_LOCK_SCOPE, getLockOptions().getLockScope() ); } if ( getLockOptions().hasAliasSpecificLockModes() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryOptionsAdapter.java b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryOptionsAdapter.java index 21f9f655df..1a1de60254 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryOptionsAdapter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryOptionsAdapter.java @@ -37,7 +37,7 @@ public abstract class QueryOptionsAdapter implements QueryOptions { @Override public LockOptions getLockOptions() { - return new LockOptions(); + return LockOptions.NONE; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MatchingIdSelectionHelper.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MatchingIdSelectionHelper.java index 425c43822e..2d22fec67f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MatchingIdSelectionHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MatchingIdSelectionHelper.java @@ -304,7 +304,7 @@ public class MatchingIdSelectionHelper { , executionContext.getSession() ); - final LockOptions lockOptions = executionContext.getQueryOptions().getLockOptions(); + final LockOptions lockOptions = executionContext.getQueryOptions().getLockOptions().makeCopy(); final LockMode lockMode = lockOptions.getLockMode(); // Acquire a WRITE lock for the rows that are about to be modified lockOptions.setLockMode( LockMode.WRITE ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java index e5378f25ec..a51ede5367 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java @@ -119,9 +119,10 @@ public class DeferredResultSetAccess extends AbstractResultSetAccess { executionContext.getCallback().registerAfterLoadAction( (session, entity, persister) -> { - ( (Session) session ).buildLockRequest( lockOptionsToUse ).lock( + ( (Session) session ).lock( persister.getEntityName(), - entity + entity, + lockOptionsToUse ); } );