HHH-15680 deprecate LockRequest and add overloads of lock() which accept LockOptions

This commit is contained in:
Gavin King 2022-11-07 10:40:23 +01:00
parent 4b7fcb5123
commit 61294250b3
5 changed files with 133 additions and 47 deletions

View File

@ -7,7 +7,6 @@
package org.hibernate; package org.hibernate;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -23,7 +22,7 @@ import static java.util.Collections.emptyList;
/** /**
* Contains a set of options describing how a row of a database table * Contains a set of options describing how a row of a database table
* mapped by an entity should be locked. For * mapped by an entity should be locked. For
* {@link Session#buildLockRequest(LockOptions)}, * {@link Session#lock(Object, LockOptions)},
* {@link Session#get(Class, Object, LockOptions)}, or * {@link Session#get(Class, Object, LockOptions)}, or
* {@link Session#refresh(Object, LockOptions)}, the relevant options * {@link Session#refresh(Object, LockOptions)}, the relevant options
* are: * are:
@ -33,6 +32,10 @@ import static java.util.Collections.emptyList;
* <li>the {@link #getLockScope() lock scope}, that is, whether the * <li>the {@link #getLockScope() lock scope}, that is, whether the
* lock extends to rows of owned collections. * lock extends to rows of owned collections.
* </ul> * </ul>
* Timeout and lock scope are ignored if the specified {@code LockMode}
* represents a flavor of {@linkplain LockMode#OPTIMISTIC optimistic}
* locking.
* <p>
* In HQL and criteria queries, lock modes can be defined in an even * In HQL and criteria queries, lock modes can be defined in an even
* more granular fashion, with the option to specify a lock mode that * more granular fashion, with the option to specify a lock mode that
* {@linkplain #setAliasSpecificLockMode(String, LockMode) applies * {@linkplain #setAliasSpecificLockMode(String, LockMode) applies
@ -42,13 +45,13 @@ import static java.util.Collections.emptyList;
*/ */
public class LockOptions implements Serializable { public class LockOptions implements Serializable {
/** /**
* Represents {@link LockMode#NONE}, where timeout and scope are * Represents {@link LockMode#NONE}, to which timeout and scope are
* not applicable. * not applicable.
*/ */
public static final LockOptions NONE = new LockOptions(LockMode.NONE); public static final LockOptions NONE = new LockOptions(LockMode.NONE);
/** /**
* Represents {@link LockMode#READ}, where timeout and scope are * Represents {@link LockMode#READ}, to which timeout and scope are
* not applicable. * not applicable.
*/ */
public static final LockOptions READ = new LockOptions(LockMode.READ); public static final LockOptions READ = new LockOptions(LockMode.READ);
@ -70,7 +73,9 @@ public class LockOptions implements Serializable {
public static final int NO_WAIT = 0; public static final int NO_WAIT = 0;
/** /**
* Indicates that there is no timeout for the lock acquisition. * Indicates that there is no timeout for the lock acquisition,
* that is, that the database should in principle wait forever
* to obtain the lock.
* *
* @see #getTimeOut * @see #getTimeOut
*/ */
@ -92,14 +97,15 @@ public class LockOptions implements Serializable {
private Boolean followOnLocking; private Boolean followOnLocking;
/** /**
* Constructs an instance with all default options. * Construct an instance with mode {@link LockMode#NONE} and
* timeout {@link #WAIT_FOREVER}.
*/ */
public LockOptions() { public LockOptions() {
} }
/** /**
* Constructs an instance with the given {@linkplain LockMode * Construct an instance with the given {@linkplain LockMode mode}
* lock mode}. * and {@link #WAIT_FOREVER}.
* *
* @param lockMode The lock mode to use * @param lockMode The lock mode to use
*/ */
@ -107,6 +113,29 @@ public class LockOptions implements Serializable {
this.lockMode = lockMode; this.lockMode = lockMode;
} }
/**
* Construct an instance with the given {@linkplain LockMode mode}
* and timeout.
*
* @param lockMode The lock mode to use
*/
public LockOptions(LockMode lockMode, int timeout) {
this.lockMode = lockMode;
this.timeout = timeout;
}
/**
* Construct an instance with the given {@linkplain LockMode mode},
* timeout, and {@link PessimisticLockScope scope}.
*
* @param lockMode The lock mode to use
*/
public LockOptions(LockMode lockMode, int timeout, PessimisticLockScope scope) {
this.lockMode = lockMode;
this.timeout = timeout;
this.scope = scope == PessimisticLockScope.EXTENDED;
}
/** /**
* Determine of the lock options are empty. * Determine of the lock options are empty.
* *

View File

@ -651,68 +651,82 @@ public interface Session extends SharedSessionContract, EntityManager {
void delete(String entityName, Object object); void delete(String entityName, Object object);
/** /**
* Obtain the specified lock level on the given managed instance association with * Obtain the specified lock level on the given managed instance associated
* this session. This may be used to: * with this session. This may be used to:
* <ul> * <ul>
* <li>perform a version check with {@link LockMode#READ}, or * <li>perform a version check with {@link LockMode#READ}, or
* <li>upgrade to a pessimistic lock with {@link LockMode#PESSIMISTIC_WRITE}). * <li>upgrade to a pessimistic lock with {@link LockMode#PESSIMISTIC_WRITE}).
* </ul> * </ul>
* This operation cascades to associated instances if the association is mapped * This operation cascades to associated instances if the association is
* with {@link org.hibernate.annotations.CascadeType#LOCK}. * mapped with {@link org.hibernate.annotations.CascadeType#LOCK}.
* <p>
* Convenient form of {@link LockRequest#lock(Object)} via
* {@link #buildLockRequest(LockOptions)}
* *
* @param object a persistent or transient instance * @param object a persistent or transient instance
* @param lockMode the lock level * @param lockMode the lock level
*
* @see #buildLockRequest(LockOptions)
* @see LockRequest#lock(Object)
*/ */
void lock(Object object, LockMode lockMode); void lock(Object object, LockMode lockMode);
/** /**
* Obtain the specified lock level on the given managed instance association with * Obtain a lock on the given managed instance associated with this session,
* this session. This may be used to: * using the given {@link LockOptions lock options}.
* <p>
* This operation cascades to associated instances if the association is
* mapped with {@link org.hibernate.annotations.CascadeType#LOCK}.
*
* @param object a persistent or transient instance
* @param lockOptions the lock options
*/
void lock(Object object, LockOptions lockOptions);
/**
* Obtain the specified lock level on the given managed instance associated
* with this session. This may be used to:
* <ul> * <ul>
* <li>perform a version check with {@link LockMode#READ}, or * <li>perform a version check with {@link LockMode#READ}, or
* <li>upgrade to a pessimistic lock with {@link LockMode#PESSIMISTIC_WRITE}). * <li>upgrade to a pessimistic lock with {@link LockMode#PESSIMISTIC_WRITE}).
* </ul> * </ul>
* This operation cascades to associated instances if the association is mapped * This operation cascades to associated instances if the association is
* with {@link org.hibernate.annotations.CascadeType#LOCK}. * mapped with {@link org.hibernate.annotations.CascadeType#LOCK}.
* <p>
* Convenient form of {@link LockRequest#lock(String, Object)} via
* {@link #buildLockRequest(LockOptions)}
* *
* @param entityName the name of the entity * @param entityName the name of the entity
* @param object a persistent or transient instance * @param object a persistent or transient instance
* @param lockMode the lock level * @param lockMode the lock level
*
* @see #buildLockRequest(LockOptions)
* @see LockRequest#lock(String, Object)
*/ */
void lock(String entityName, Object object, LockMode lockMode); void lock(String entityName, Object object, LockMode lockMode);
/**
* Obtain a lock on the given managed instance associated with this session,
* using the given {@link LockOptions lock options}.
* <p>
* This operation cascades to associated instances if the association is
* mapped with {@link org.hibernate.annotations.CascadeType#LOCK}.
*
* @param entityName the name of the entity
* @param lockOptions the lock options
*/
void lock(String entityName, Object object, LockOptions lockOptions);
/** /**
* Build a new {@link LockRequest lock request} that specifies: * Build a new {@link LockRequest lock request} that specifies:
* <ul> * <ul>
* <li>the {@link LockMode} to use, * <li>the {@link LockMode} to use,
* <li>the pessimistic lock timeout, and * <li>the {@linkplain LockRequest#setTimeOut(int) pessimistic lock timeout},
* <li>the {@linkplain LockRequest#setScope(boolean) scope} of the lock. * and
* <li>the {@linkplain LockRequest#setLockScope(PessimisticLockScope) scope}
* that is, whether the lock extends to rows of owned collections.
* </ul> * </ul>
* Timeout and scope are ignored if the specified {@code LockMode} represents a * Timeout and scope are ignored if the specified {@code LockMode} represents
* form of {@linkplain LockMode#OPTIMISTIC optimistic} locking. * a flavor of {@linkplain LockMode#OPTIMISTIC optimistic} locking.
* <p> * <p>
* Call {@link LockRequest#lock(Object)} to actually obtain the requested lock * Call {@link LockRequest#lock(Object)} to actually obtain the requested lock
* on a managed entity instance. * on a managed entity instance.
* <p>
* Example usage:
* {@code session.buildLockRequest().setLockMode(LockMode.PESSIMISTIC_WRITE).setTimeOut(60000).lock(entity);}
* *
* @param lockOptions contains the lock level * @param lockOptions contains the lock level
* *
* @return a {@link LockRequest} that can be used to lock any given object. * @return a {@link LockRequest} that can be used to lock any given object.
*
* @deprecated use {@link #lock(Object, LockOptions)}
*/ */
@Deprecated(since = "6.2")
LockRequest buildLockRequest(LockOptions lockOptions); LockRequest buildLockRequest(LockOptions lockOptions);
/** /**
@ -720,8 +734,10 @@ public interface Session extends SharedSessionContract, EntityManager {
* from the underlying database. This may be useful: * from the underlying database. This may be useful:
* <ul> * <ul>
* <li>when a database trigger alters the object state upon insert or update * <li>when a database trigger alters the object state upon insert or update
* <li>after {@linkplain #createMutationQuery(String) executing} any HQL update or delete statement * <li>after {@linkplain #createMutationQuery(String) executing} any HQL update
* <li>after {@linkplain #createNativeMutationQuery(String) executing} a native SQL statement * or delete statement
* <li>after {@linkplain #createNativeMutationQuery(String) executing} a native
* SQL statement
* <li>after inserting a {@link java.sql.Blob} or {@link java.sql.Clob} * <li>after inserting a {@link java.sql.Blob} or {@link java.sql.Clob}
* </ul> * </ul>
* This operation cascades to associated instances if the association is mapped * This operation cascades to associated instances if the association is mapped
@ -736,8 +752,10 @@ public interface Session extends SharedSessionContract, EntityManager {
* from the underlying database. This may be useful: * from the underlying database. This may be useful:
* <ul> * <ul>
* <li>when a database trigger alters the object state upon insert or update * <li>when a database trigger alters the object state upon insert or update
* <li>after {@linkplain #createMutationQuery(String) executing} any HQL update or delete statement * <li>after {@linkplain #createMutationQuery(String) executing} any HQL update
* <li>after {@linkplain #createNativeMutationQuery(String) executing} a native SQL statement * or delete statement
* <li>after {@linkplain #createNativeMutationQuery(String) executing} a native
* SQL statement
* <li>after inserting a {@link java.sql.Blob} or {@link java.sql.Clob} * <li>after inserting a {@link java.sql.Blob} or {@link java.sql.Clob}
* </ul> * </ul>
* This operation cascades to associated instances if the association is mapped * This operation cascades to associated instances if the association is mapped
@ -1206,19 +1224,26 @@ public interface Session extends SharedSessionContract, EntityManager {
SharedSessionBuilder sessionWithOptions(); SharedSessionBuilder sessionWithOptions();
/** /**
* Contains locking details (LockMode, Timeout and Scope). * A set of {@linkplain LockOptions locking options} attached
* to the session.
*
* @deprecated simply construct a {@link LockOptions} and pass
* it to {@link #lock(Object, LockOptions)}.
*/ */
@Deprecated(since = "6.2")
interface LockRequest { interface LockRequest {
/** /**
* Constant usable as a timeout value indicating that no wait semantics should * A timeout value indicating that the database should not
* be used in attempting to acquire locks. * wait at all to acquire a pessimistic lock which is not
* immediately available.
*/ */
int PESSIMISTIC_NO_WAIT = 0; int PESSIMISTIC_NO_WAIT = LockOptions.NO_WAIT;
/** /**
* Constant usable as a timeout value indicating that attempting to acquire * A timeout value indicating that attempting to acquire
* locks should be allowed to wait forever, that is, that there's no timeout. * that there is no timeout for the lock acquisition.
*/ */
int PESSIMISTIC_WAIT_FOREVER = -1; int PESSIMISTIC_WAIT_FOREVER = LockOptions.WAIT_FOREVER;
/** /**
* Get the lock mode. * Get the lock mode.

View File

@ -882,6 +882,16 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
} }
@Override @Override
public void lock(String entityName, Object object, LockOptions lockOptions) {
delegate.lock( entityName, object, lockOptions );
}
@Override
public void lock(Object object, LockOptions lockOptions) {
delegate.lock( object, lockOptions );
}
@Override @Deprecated
public LockRequest buildLockRequest(LockOptions lockOptions) { public LockRequest buildLockRequest(LockOptions lockOptions) {
return delegate.buildLockRequest( lockOptions ); return delegate.buildLockRequest( lockOptions );
} }

View File

@ -281,6 +281,17 @@ public class SessionLazyDelegator implements Session {
} }
@Override @Override
public void lock(Object object, LockOptions lockOptions) {
this.lazySession.get().lock( object, lockOptions );
}
@Override
public void lock(String entityName, Object object, LockOptions lockOptions) {
this.lazySession.get().lock( entityName, object, lockOptions );
}
@Override
@Deprecated
public LockRequest buildLockRequest(LockOptions lockOptions) { public LockRequest buildLockRequest(LockOptions lockOptions) {
return this.lazySession.get().buildLockRequest( lockOptions ); return this.lazySession.get().buildLockRequest( lockOptions );
} }

View File

@ -674,12 +674,22 @@ public class SessionImpl
// lock() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // lock() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public void lock(Object object, LockOptions lockOptions) {
fireLock( new LockEvent( object, lockOptions, this ) );
}
@Override
public void lock(String entityName, Object object, LockOptions lockOptions) {
fireLock( new LockEvent( entityName, object, lockOptions, this ) );
}
@Override @Override
public void lock(String entityName, Object object, LockMode lockMode) throws HibernateException { public void lock(String entityName, Object object, LockMode lockMode) throws HibernateException {
fireLock( new LockEvent( entityName, object, lockMode, this ) ); fireLock( new LockEvent( entityName, object, lockMode, this ) );
} }
@Override @Override @Deprecated
public LockRequest buildLockRequest(LockOptions lockOptions) { public LockRequest buildLockRequest(LockOptions lockOptions) {
return new LockRequestImpl( lockOptions ); return new LockRequestImpl( lockOptions );
} }
@ -2109,6 +2119,7 @@ public class SessionImpl
} }
} }
@Deprecated
private class LockRequestImpl implements LockRequest { private class LockRequestImpl implements LockRequest {
private final LockOptions lockOptions; private final LockOptions lockOptions;