diff --git a/api/src/main/java/jakarta/persistence/EntityManager.java b/api/src/main/java/jakarta/persistence/EntityManager.java index 9416ff34..e335461a 100644 --- a/api/src/main/java/jakarta/persistence/EntityManager.java +++ b/api/src/main/java/jakarta/persistence/EntityManager.java @@ -480,6 +480,54 @@ public T getReference(Class entityClass, public void lock(Object entity, LockModeType lockMode, Map properties); + /** + * Lock an entity instance that is contained in the persistence + * context with the specified lock mode type, using specified + * {@linkplain LockOption options}. + *

If a pessimistic lock mode type is specified and the entity + * contains a version attribute, the persistence provider must + * also perform optimistic version checks when obtaining the + * database lock. If these checks fail, the + * OptimisticLockException will be thrown. + *

If the lock mode type is pessimistic and the entity instance + * is found but cannot be locked: + *

    + *
  • the PessimisticLockException will be thrown + * if the database locking failure causes transaction-level + * rollback + *
  • the LockTimeoutException will be thrown if + * the database locking failure causes only statement-level + * rollback + *
+ *

If a vendor-specific {@link LockOption} is not recognized, + * it is silently ignored. + *

Portable applications should not rely on the standard + * {@linkplain Timeout timeout option}. Depending on the database + * in use and the locking mechanisms used by the provider, the + * option may or may not be observed. + * @param entity entity instance + * @param lockMode lock mode + * @param options standard and vendor-specific options + * @throws IllegalArgumentException if the instance is not an + * entity or is a detached entity + * @throws TransactionRequiredException if there is no + * transaction or if invoked on an entity manager which + * has not been joined to the current transaction + * @throws EntityNotFoundException if the entity does not exist + * in the database when pessimistic locking is + * performed + * @throws OptimisticLockException if the optimistic version + * check fails + * @throws PessimisticLockException if pessimistic locking fails + * and the transaction is rolled back + * @throws LockTimeoutException if pessimistic locking fails and + * only the statement is rolled back + * @throws PersistenceException if an unsupported lock call is made + * @since 3.2 + */ + public void lock(Object entity, LockModeType lockMode, + LockOption... options); + /** * Refresh the state of the instance from the database, * overwriting changes made to the entity, if any. diff --git a/api/src/main/java/jakarta/persistence/LockOption.java b/api/src/main/java/jakarta/persistence/LockOption.java new file mode 100644 index 00000000..0fab0f3c --- /dev/null +++ b/api/src/main/java/jakarta/persistence/LockOption.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2008, 2020 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +// Contributors: +// Gavin King - 3.2 + + +package jakarta.persistence; + +/** + * An option influencing the behavior of {@link EntityManager#lock}. + * Built-in options control {@linkplain PessimisticLockScope scope}, + * and {@linkplain Timeout timeouts}. + * + *

This interface may be implemented by custom provider-specific + * options which extend the options defined by the specification. + * + * @see LockModeType + * @see PessimisticLockScope + * @see Timeout + * + * @see EntityManager#lock(Object, LockModeType, LockOption...) + * + * @since 3.2 + */ +public interface LockOption { +} diff --git a/api/src/main/java/jakarta/persistence/PessimisticLockScope.java b/api/src/main/java/jakarta/persistence/PessimisticLockScope.java index e1541ff1..b0495233 100644 --- a/api/src/main/java/jakarta/persistence/PessimisticLockScope.java +++ b/api/src/main/java/jakarta/persistence/PessimisticLockScope.java @@ -27,7 +27,7 @@ * * @since 2.0 */ -public enum PessimisticLockScope implements FindOption, RefreshOption { +public enum PessimisticLockScope implements FindOption, RefreshOption, LockOption { /** * This value defines the default behavior for pessimistic locking. diff --git a/api/src/main/java/jakarta/persistence/Timeout.java b/api/src/main/java/jakarta/persistence/Timeout.java index 19a85e43..a509e2c2 100644 --- a/api/src/main/java/jakarta/persistence/Timeout.java +++ b/api/src/main/java/jakarta/persistence/Timeout.java @@ -22,7 +22,7 @@ * * @since 3.2 */ -public class Timeout implements FindOption, RefreshOption { +public class Timeout implements FindOption, RefreshOption, LockOption { private final int milliseconds; private Timeout(int milliseconds) { diff --git a/spec/src/main/asciidoc/ch03-entity-operations.adoc b/spec/src/main/asciidoc/ch03-entity-operations.adoc index b0683ff7..3429a522 100644 --- a/spec/src/main/asciidoc/ch03-entity-operations.adoc +++ b/spec/src/main/asciidoc/ch03-entity-operations.adoc @@ -513,6 +513,54 @@ public interface EntityManager extends AutoCloseable { public void lock(Object entity, LockModeType lockMode, Map properties); + /** + * Lock an entity instance that is contained in the persistence + * context with the specified lock mode type, using specified + * {@linkplain LockOption options}. + *

If a pessimistic lock mode type is specified and the entity + * contains a version attribute, the persistence provider must + * also perform optimistic version checks when obtaining the + * database lock. If these checks fail, the + * OptimisticLockException will be thrown. + *

If the lock mode type is pessimistic and the entity instance + * is found but cannot be locked: + *

    + *
  • the PessimisticLockException will be thrown + * if the database locking failure causes transaction-level + * rollback + *
  • the LockTimeoutException will be thrown if + * the database locking failure causes only statement-level + * rollback + *
+ *

If a vendor-specific {@link LockOption} is not recognized, + * it is silently ignored. + *

Portable applications should not rely on the standard + * {@linkplain Timeout timeout option}. Depending on the database + * in use and the locking mechanisms used by the provider, the + * option may or may not be observed. + * @param entity entity instance + * @param lockMode lock mode + * @param options standard and vendor-specific options + * @throws IllegalArgumentException if the instance is not an + * entity or is a detached entity + * @throws TransactionRequiredException if there is no + * transaction or if invoked on an entity manager which + * has not been joined to the current transaction + * @throws EntityNotFoundException if the entity does not exist + * in the database when pessimistic locking is + * performed + * @throws OptimisticLockException if the optimistic version + * check fails + * @throws PessimisticLockException if pessimistic locking fails + * and the transaction is rolled back + * @throws LockTimeoutException if pessimistic locking fails and + * only the statement is rolled back + * @throws PersistenceException if an unsupported lock call is made + * @since 3.2 + */ + public void lock(Object entity, LockModeType lockMode, + LockOption... options); + /** * Refresh the state of the instance from the database, * overwriting changes made to the entity, if any.