From ed6ec6b3694ca8c8536c9ba15e3f03d269310357 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 11 Aug 2023 14:27:34 +0200 Subject: [PATCH 1/6] introduce FindOption interface and new overloads of EM.find() see #383. --- .../persistence/CacheRetrieveMode.java | 2 +- .../jakarta/persistence/CacheStoreMode.java | 2 +- .../java/jakarta/persistence/EntityGraph.java | 2 +- .../jakarta/persistence/EntityManager.java | 113 ++++++++++++++++++ .../java/jakarta/persistence/FindOption.java | 40 +++++++ .../jakarta/persistence/LockModeType.java | 3 +- .../jakarta/persistence/NamedSubgraph.java | 2 +- .../persistence/PessimisticLockScope.java | 2 +- .../java/jakarta/persistence/Timeout.java | 68 +++++++++++ .../main/asciidoc/ch03-entity-operations.adoc | 113 ++++++++++++++++++ 10 files changed, 340 insertions(+), 7 deletions(-) create mode 100644 api/src/main/java/jakarta/persistence/FindOption.java create mode 100644 api/src/main/java/jakarta/persistence/Timeout.java diff --git a/api/src/main/java/jakarta/persistence/CacheRetrieveMode.java b/api/src/main/java/jakarta/persistence/CacheRetrieveMode.java index c503145e..0bc327dc 100644 --- a/api/src/main/java/jakarta/persistence/CacheRetrieveMode.java +++ b/api/src/main/java/jakarta/persistence/CacheRetrieveMode.java @@ -24,7 +24,7 @@ * * @since 2.0 */ -public enum CacheRetrieveMode { +public enum CacheRetrieveMode implements FindOption { /** * Read entity data from the cache: this is diff --git a/api/src/main/java/jakarta/persistence/CacheStoreMode.java b/api/src/main/java/jakarta/persistence/CacheStoreMode.java index 41f2e580..31528464 100644 --- a/api/src/main/java/jakarta/persistence/CacheStoreMode.java +++ b/api/src/main/java/jakarta/persistence/CacheStoreMode.java @@ -24,7 +24,7 @@ * * @since 2.0 */ -public enum CacheStoreMode { +public enum CacheStoreMode implements FindOption { /** * Insert entity data into cache when read from database diff --git a/api/src/main/java/jakarta/persistence/EntityGraph.java b/api/src/main/java/jakarta/persistence/EntityGraph.java index 353aacd2..5e0f8919 100644 --- a/api/src/main/java/jakarta/persistence/EntityGraph.java +++ b/api/src/main/java/jakarta/persistence/EntityGraph.java @@ -39,7 +39,7 @@ public interface EntityGraph extends Graph { * Return the name of a named EntityGraph (an entity graph * defined by means of the NamedEntityGraph * annotation, XML descriptor element, or added by means of the - * addNamedEntityGraph method. Returns null if the + * addNamedEntityGraph method). Returns null if the * EntityGraph is not a named EntityGraph. */ public String getName(); diff --git a/api/src/main/java/jakarta/persistence/EntityManager.java b/api/src/main/java/jakarta/persistence/EntityManager.java index ff164582..1509d469 100644 --- a/api/src/main/java/jakarta/persistence/EntityManager.java +++ b/api/src/main/java/jakarta/persistence/EntityManager.java @@ -235,6 +235,119 @@ public T find(Class entityClass, Object primaryKey, LockModeType lockMode, Map properties); + /** + * Find an instance of the given entity class by primary key, + * using the specified {@linkplain FindOption options}. + * Search for an entity with the specified class and primary key. + * If the given options include a {@link LockModeType}, lock it + * with respect to the specified lock type. + * If the entity instance is contained in the persistence context, + * it is returned from there. + *

If the entity is found within the persistence context and + * the lock mode type is pessimistic and the entity has a version + * attribute, the persistence provider must 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 {@linkplain FindOption option} 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, this + * option may or may not be observed. + * @param entityClass entity class + * @param primaryKey primary key + * @param options standard and vendor-specific options + * @return the found entity instance or null if the entity does + * not exist + * @throws IllegalArgumentException if there are contradictory + * options, if the first argument does not denote an entity + * type belonging to the persistence unit, or if the second + * argument is not a valid non-null instance of the entity + * primary key type + * @throws TransactionRequiredException if there is no transaction + * and a lock mode other than NONE is + * specified or if invoked on an entity manager which has + * not been joined to the current transaction and a lock + * mode other than NONE is specified + * @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 T find(Class entityClass, Object primaryKey, + FindOption... options); + + /** + * Find an instance of the root entity of the given {@link EntityGraph} + * by primary key, using the specified {@linkplain FindOption options}, + * and interpreting the {@code EntityGraph} as a load graph. + * Search for an entity with the specified type and primary key. + * If the given options include a {@link LockModeType}, lock it + * with respect to the specified lock type. + * If the entity instance is contained in the persistence context, + * it is returned from there. + *

If the entity is found within the persistence context and + * the lock mode type is pessimistic and the entity has a version + * attribute, the persistence provider must 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 {@linkplain FindOption option} 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, this + * option may or may not be observed. + * @param entityGraph entity graph interpreted as a load graph + * @param primaryKey primary key + * @param options standard and vendor-specific options + * @return the found entity instance or null if the entity does + * not exist + * @throws IllegalArgumentException if there are contradictory + * options, if the first argument does not denote an entity + * type belonging to the persistence unit, or if the second + * argument is not a valid non-null instance of the entity + * primary key type + * @throws TransactionRequiredException if there is no transaction + * and a lock mode other than NONE is + * specified or if invoked on an entity manager which has + * not been joined to the current transaction and a lock + * mode other than NONE is specified + * @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 T find(EntityGraph entityGraph, Object primaryKey, + FindOption... options); + /** * Get an instance, whose state may be lazily fetched. * If the requested instance does not exist in the database, diff --git a/api/src/main/java/jakarta/persistence/FindOption.java b/api/src/main/java/jakarta/persistence/FindOption.java new file mode 100644 index 00000000..e441f801 --- /dev/null +++ b/api/src/main/java/jakarta/persistence/FindOption.java @@ -0,0 +1,40 @@ +/* + * 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#find}. + * Built-in options control {@linkplain LockModeType locking}, + * {@linkplain CacheRetrieveMode cache interaction}, 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 CacheRetrieveMode + * @see CacheStoreMode + * @see Timeout + * + * @see EntityManager#find(Class, Object, FindOption...) + * @see EntityManager#find(EntityGraph, Object, FindOption...) + * + * @since 3.2 + */ +public interface FindOption { +} diff --git a/api/src/main/java/jakarta/persistence/LockModeType.java b/api/src/main/java/jakarta/persistence/LockModeType.java index 3a6640c0..6eac8bcc 100644 --- a/api/src/main/java/jakarta/persistence/LockModeType.java +++ b/api/src/main/java/jakarta/persistence/LockModeType.java @@ -126,8 +126,7 @@ * @since 1.0 * */ -public enum LockModeType -{ +public enum LockModeType implements FindOption { /** * Synonymous with OPTIMISTIC. * OPTIMISTIC is to be preferred for new diff --git a/api/src/main/java/jakarta/persistence/NamedSubgraph.java b/api/src/main/java/jakarta/persistence/NamedSubgraph.java index 9915c7f9..05ed12a4 100644 --- a/api/src/main/java/jakarta/persistence/NamedSubgraph.java +++ b/api/src/main/java/jakarta/persistence/NamedSubgraph.java @@ -47,7 +47,7 @@ * must be specified when this subgraph is extending a definition * on behalf of a subclass. */ - Class type() default void.class; + Class type() default void.class; /** * (Required) The list of the attributes of the class that must diff --git a/api/src/main/java/jakarta/persistence/PessimisticLockScope.java b/api/src/main/java/jakarta/persistence/PessimisticLockScope.java index 0ba307b8..91bde605 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 { +public enum PessimisticLockScope implements FindOption { /** * 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 new file mode 100644 index 00000000..b0761d80 --- /dev/null +++ b/api/src/main/java/jakarta/persistence/Timeout.java @@ -0,0 +1,68 @@ +/* + * 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; + +/** + * Specifies a timeout for a database request. This option is + * always a hint, and may be ignored by the provider. + * + * @since 3.2 + */ +public class Timeout implements FindOption { + private final int milliseconds; + + private Timeout(int milliseconds) { + this.milliseconds = milliseconds; + } + + /** + * Specify a timeout in seconds. + * (Abbreviation of {@link #seconds(int)}.) + */ + public Timeout s(int seconds) { + return new Timeout(seconds*1_000); + } + + /** + * Specify a timeout in milliseconds. + * (Abbreviation of {@link #milliseconds(int)}.) + */ + public Timeout ms(int milliseconds) { + return new Timeout(milliseconds); + } + + /** + * Specify a timeout in seconds. + */ + public Timeout seconds(int seconds) { + return new Timeout(seconds*1_000); + } + + /** + * Specify a timeout in milliseconds. + */ + public Timeout milliseconds(int milliseconds) { + return new Timeout(milliseconds); + } + + /** + * The timeout in milliseconds. + */ + public int milliseconds() { + return milliseconds; + } +} diff --git a/spec/src/main/asciidoc/ch03-entity-operations.adoc b/spec/src/main/asciidoc/ch03-entity-operations.adoc index 7a13c7a2..6dce4f4c 100644 --- a/spec/src/main/asciidoc/ch03-entity-operations.adoc +++ b/spec/src/main/asciidoc/ch03-entity-operations.adoc @@ -268,6 +268,119 @@ public interface EntityManager extends AutoCloseable { LockModeType lockMode, Map properties); + /** + * Find an instance of the given entity class by primary key, + * using the specified {@linkplain FindOption options}. + * Search for an entity with the specified class and primary key. + * If the given options include a {@link LockModeType}, lock it + * with respect to the specified lock type. + * If the entity instance is contained in the persistence context, + * it is returned from there. + *

If the entity is found within the persistence context and + * the lock mode type is pessimistic and the entity has a version + * attribute, the persistence provider must 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 {@linkplain FindOption option} 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, this + * option may or may not be observed. + * @param entityClass entity class + * @param primaryKey primary key + * @param options standard and vendor-specific options + * @return the found entity instance or null if the entity does + * not exist + * @throws IllegalArgumentException if there are contradictory + * options, if the first argument does not denote an entity + * type belonging to the persistence unit, or if the second + * argument is not a valid non-null instance of the entity + * primary key type + * @throws TransactionRequiredException if there is no transaction + * and a lock mode other than NONE is + * specified or if invoked on an entity manager which has + * not been joined to the current transaction and a lock + * mode other than NONE is specified + * @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 T find(Class entityClass, Object primaryKey, + FindOption... options); + + /** + * Find an instance of the root entity of the given {@link EntityGraph} + * by primary key, using the specified {@linkplain FindOption options}, + * and interpreting the {@code EntityGraph} as a load graph. + * Search for an entity with the specified type and primary key. + * If the given options include a {@link LockModeType}, lock it + * with respect to the specified lock type. + * If the entity instance is contained in the persistence context, + * it is returned from there. + *

If the entity is found within the persistence context and + * the lock mode type is pessimistic and the entity has a version + * attribute, the persistence provider must 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 {@linkplain FindOption option} 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, this + * option may or may not be observed. + * @param entityGraph entity graph interpreted as a load graph + * @param primaryKey primary key + * @param options standard and vendor-specific options + * @return the found entity instance or null if the entity does + * not exist + * @throws IllegalArgumentException if there are contradictory + * options, if the first argument does not denote an entity + * type belonging to the persistence unit, or if the second + * argument is not a valid non-null instance of the entity + * primary key type + * @throws TransactionRequiredException if there is no transaction + * and a lock mode other than NONE is + * specified or if invoked on an entity manager which has + * not been joined to the current transaction and a lock + * mode other than NONE is specified + * @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 T find(EntityGraph entityGraph, Object primaryKey, + FindOption... options); + /** * Get an instance, whose state may be lazily fetched. * If the requested instance does not exist in the database, From 349cffe14acdfbc002de3a1af65ccc641fa87617 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 11 Aug 2023 15:30:07 +0200 Subject: [PATCH 2/6] add Graph.removeAttributeNode() The purpose of these operations is to suppress defaulted EAGER association loading in load graphs, but it can be used more broadly to suppress loading of any graph node. see #383. --- .../main/java/jakarta/persistence/Graph.java | 32 +++++++++++++++++++ .../main/asciidoc/ch03-entity-operations.adoc | 32 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/api/src/main/java/jakarta/persistence/Graph.java b/api/src/main/java/jakarta/persistence/Graph.java index d47b5b86..61e71913 100644 --- a/api/src/main/java/jakarta/persistence/Graph.java +++ b/api/src/main/java/jakarta/persistence/Graph.java @@ -55,6 +55,38 @@ public interface Graph { */ public void addAttributeNode(Attribute attribute); + /** + * Remove an attribute node from the entity graph. + * When this graph is interpreted as a load graph, this operation + * suppresses inclusion of an attribute mapped for eager fetching. + * The effect of this call may be overridden by subsequent + * invocations of {@link #addAttributeNode} or {@link #addSubgraph}. + * @param attributeName name of the attribute + * @since 3.2 + */ + public void removeAttributeNode(String attributeName); + + /** + * Remove an attribute node from the entity graph. + * When this graph is interpreted as a load graph, this operation + * suppresses inclusion of an attribute mapped for eager fetching. + * The effect of this call may be overridden by subsequent + * invocations of {@link #addAttributeNode} or {@link #addSubgraph}. + * @param attribute attribute + * @since 3.2 + */ + public void removeAttributeNode(Attribute attribute); + + /** + * Remove all attribute nodes of the given attribute types. + * When this graph is interpreted as a load graph, this operation + * suppresses inclusion of attributes mapped for eager fetching. + * The effect of this call may be overridden by subsequent + * invocations of {@link #addAttributeNode} or {@link #addSubgraph}. + * @since 3.2 + */ + public void removeAttributeNodes(Attribute.PersistentAttributeType nodeTypes); + /** * Add one or more attribute nodes to the entity graph. * diff --git a/spec/src/main/asciidoc/ch03-entity-operations.adoc b/spec/src/main/asciidoc/ch03-entity-operations.adoc index 6dce4f4c..933a66d9 100644 --- a/spec/src/main/asciidoc/ch03-entity-operations.adoc +++ b/spec/src/main/asciidoc/ch03-entity-operations.adoc @@ -2931,6 +2931,38 @@ public interface Graph { */ public void addAttributeNode(Attribute attribute); + /** + * Remove an attribute node from the entity graph. + * When this graph is interpreted as a load graph, this operation + * suppresses inclusion of an attribute mapped for eager fetching. + * The effect of this call may be overridden by subsequent + * invocations of {@link #addAttributeNode} or {@link #addSubgraph}. + * @param attributeName name of the attribute + * @since 3.2 + */ + public void removeAttributeNode(String attributeName); + + /** + * Remove an attribute node from the entity graph. + * When this graph is interpreted as a load graph, this operation + * suppresses inclusion of an attribute mapped for eager fetching. + * The effect of this call may be overridden by subsequent + * invocations of {@link #addAttributeNode} or {@link #addSubgraph}. + * @param attribute attribute + * @since 3.2 + */ + public void removeAttributeNode(Attribute attribute); + + /** + * Remove all attribute nodes of the given attribute types. + * When this graph is interpreted as a load graph, this operation + * suppresses inclusion of attributes mapped for eager fetching. + * The effect of this call may be overridden by subsequent + * invocations of {@link #addAttributeNode} or {@link #addSubgraph}. + * @since 3.2 + */ + public void removeAttributeNodes(Attribute.PersistentAttributeType nodeTypes); + /** * Add one or more attribute nodes to the entity graph. * From 9f5d06b65f49f52c5f937d57b13e1e81e78c4350 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 11 Aug 2023 17:13:53 +0200 Subject: [PATCH 3/6] add EntityManager/Query.setCacheRetrieveMode()/setCacheStoreMode() see #383. --- .../persistence/CacheRetrieveMode.java | 3 + .../jakarta/persistence/CacheStoreMode.java | 3 + .../jakarta/persistence/EntityManager.java | 30 +++- .../main/java/jakarta/persistence/Query.java | 34 ++++ .../persistence/StoredProcedureQuery.java | 20 +++ .../java/jakarta/persistence/TypedQuery.java | 20 +++ .../main/asciidoc/ch03-entity-operations.adoc | 158 +++++++++++++++++- 7 files changed, 266 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/jakarta/persistence/CacheRetrieveMode.java b/api/src/main/java/jakarta/persistence/CacheRetrieveMode.java index 0bc327dc..f2876364 100644 --- a/api/src/main/java/jakarta/persistence/CacheRetrieveMode.java +++ b/api/src/main/java/jakarta/persistence/CacheRetrieveMode.java @@ -22,6 +22,9 @@ * specify the behavior when data is retrieved by the * find methods and by queries. * + * @see EntityManager#setCacheRetrieveMode(CacheRetrieveMode) + * @see Query#setCacheRetrieveMode(CacheRetrieveMode) + * * @since 2.0 */ public enum CacheRetrieveMode implements FindOption { diff --git a/api/src/main/java/jakarta/persistence/CacheStoreMode.java b/api/src/main/java/jakarta/persistence/CacheStoreMode.java index 31528464..6761cd9a 100644 --- a/api/src/main/java/jakarta/persistence/CacheStoreMode.java +++ b/api/src/main/java/jakarta/persistence/CacheStoreMode.java @@ -22,6 +22,9 @@ * the behavior when data is read from the database and when data is * committed into the database. * + * @see EntityManager#setCacheStoreMode(CacheStoreMode) + * @see Query#setCacheStoreMode(CacheStoreMode) + * * @since 2.0 */ public enum CacheStoreMode implements FindOption { diff --git a/api/src/main/java/jakarta/persistence/EntityManager.java b/api/src/main/java/jakarta/persistence/EntityManager.java index 1509d469..93627f10 100644 --- a/api/src/main/java/jakarta/persistence/EntityManager.java +++ b/api/src/main/java/jakarta/persistence/EntityManager.java @@ -642,7 +642,35 @@ public void refresh(Object entity, LockModeType lockMode, */ public LockModeType getLockMode(Object entity); - /** + /** + * Set the cache retrieval mode that is in effect during + * query execution. This cache retrieval mode overrides the + * cache retrieve mode in use by the entity manager. + * @param cacheRetrieveMode cache retrieval mode + * @since 3.2 + */ + public void setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode); + + /** + * Set the default cache storage mode for this persistence context. + * @param cacheStoreMode cache storage mode + * @since 3.2 + */ + public void setCacheStoreMode(CacheStoreMode cacheStoreMode); + + /** + * The cache retrieval mode for this persistence context. + * @since 3.2 + */ + public CacheRetrieveMode getCacheRetrieveMode(); + + /** + * The cache storage mode for this persistence context. + * @since 3.2 + */ + public CacheStoreMode getCacheStoreMode(); + + /** * Set an entity manager property or hint. * If a vendor-specific property or hint is not recognized, it is * silently ignored. diff --git a/api/src/main/java/jakarta/persistence/Query.java b/api/src/main/java/jakarta/persistence/Query.java index 0910e6e8..3748e745 100644 --- a/api/src/main/java/jakarta/persistence/Query.java +++ b/api/src/main/java/jakarta/persistence/Query.java @@ -512,6 +512,40 @@ Query setParameter(int position, Date value, */ LockModeType getLockMode(); + /** + * Set the cache retrieval mode that is in effect during + * query execution. This cache retrieval mode overrides the + * cache retrieve mode in use by the entity manager. + * @param cacheRetrieveMode cache retrieval mode + * @return the same query instance + * @since 3.2 + */ + Query setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode); + + /** + * Set the cache storage mode that is in effect during + * query execution. This cache storage mode overrides the + * cache storage mode in use by the entity manager. + * @param cacheStoreMode cache storage mode + * @return the same query instance + * @since 3.2 + */ + Query setCacheStoreMode(CacheStoreMode cacheStoreMode); + + /** + * The cache retrieval mode that will be in effect during + * query execution. + * @since 3.2 + */ + CacheRetrieveMode getCacheRetrieveMode(); + + /** + * The cache storage mode that will be in effect during + * query execution. + * @since 3.2 + */ + CacheStoreMode getCacheStoreMode(); + /** * Return an object of the specified type to allow access to * the provider-specific API. If the provider's query diff --git a/api/src/main/java/jakarta/persistence/StoredProcedureQuery.java b/api/src/main/java/jakarta/persistence/StoredProcedureQuery.java index b77a5af3..7c814d8d 100644 --- a/api/src/main/java/jakarta/persistence/StoredProcedureQuery.java +++ b/api/src/main/java/jakarta/persistence/StoredProcedureQuery.java @@ -261,6 +261,26 @@ StoredProcedureQuery setParameter(int position, */ StoredProcedureQuery setFlushMode(FlushModeType flushMode); + /** + * Set the cache retrieval mode that is in effect during + * query execution. This cache retrieval mode overrides the + * cache retrieve mode in use by the entity manager. + * @param cacheRetrieveMode cache retrieval mode + * @return the same query instance + * @since 3.2 + */ + StoredProcedureQuery setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode); + + /** + * Set the cache storage mode that is in effect during + * query execution. This cache storage mode overrides the + * cache storage mode in use by the entity manager. + * @param cacheStoreMode cache storage mode + * @return the same query instance + * @since 3.2 + */ + StoredProcedureQuery setCacheStoreMode(CacheStoreMode cacheStoreMode); + /** * Register a positional parameter. * All parameters must be registered. diff --git a/api/src/main/java/jakarta/persistence/TypedQuery.java b/api/src/main/java/jakarta/persistence/TypedQuery.java index e759c7df..51bb93e2 100644 --- a/api/src/main/java/jakarta/persistence/TypedQuery.java +++ b/api/src/main/java/jakarta/persistence/TypedQuery.java @@ -316,4 +316,24 @@ TypedQuery setParameter(int position, Date value, */ TypedQuery setLockMode(LockModeType lockMode); + /** + * Set the cache retrieval mode that is in effect during + * query execution. This cache retrieval mode overrides the + * cache retrieve mode in use by the entity manager. + * @param cacheRetrieveMode cache retrieval mode + * @return the same query instance + * @since 3.2 + */ + TypedQuery setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode); + + /** + * Set the cache storage mode that is in effect during + * query execution. This cache storage mode overrides the + * cache storage mode in use by the entity manager. + * @param cacheStoreMode cache storage mode + * @return the same query instance + * @since 3.2 + */ + TypedQuery setCacheStoreMode(CacheStoreMode cacheStoreMode); + } diff --git a/spec/src/main/asciidoc/ch03-entity-operations.adoc b/spec/src/main/asciidoc/ch03-entity-operations.adoc index 933a66d9..29d45cd5 100644 --- a/spec/src/main/asciidoc/ch03-entity-operations.adoc +++ b/spec/src/main/asciidoc/ch03-entity-operations.adoc @@ -675,6 +675,34 @@ public interface EntityManager extends AutoCloseable { */ public LockModeType getLockMode(Object entity); + /** + * Set the cache retrieval mode that is in effect during + * query execution. This cache retrieval mode overrides the + * cache retrieve mode in use by the entity manager. + * @param cacheRetrieveMode cache retrieval mode + * @since 3.2 + */ + public void setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode); + + /** + * Set the default cache storage mode for this persistence context. + * @param cacheStoreMode cache storage mode + * @since 3.2 + */ + public void setCacheStoreMode(CacheStoreMode cacheStoreMode); + + /** + * The cache retrieval mode for this persistence context. + * @since 3.2 + */ + public CacheRetrieveMode getCacheRetrieveMode(); + + /** + * The cache storage mode for this persistence context. + * @since 3.2 + */ + public CacheStoreMode getCacheStoreMode(); + /** * Set an entity manager property or hint. * If a vendor-specific property or hint is not recognized, it is @@ -1028,7 +1056,7 @@ public interface EntityManager extends AutoCloseable { * the given name * @since 2.1 */ - public EntityGraph getEntityGraph(String graphName); + public EntityGraph getEntityGraph(String graphName); /** * Return all named EntityGraphs that have been defined for the provided @@ -4294,7 +4322,10 @@ public interface Query { * @throws IllegalArgumentException if the parameter does not * correspond to a parameter of the query * @since 2.0 + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") Query setParameter(Parameter param, Calendar value, TemporalType temporalType); @@ -4307,7 +4338,10 @@ public interface Query { * @throws IllegalArgumentException if the parameter does not * correspond to a parameter of the query * @since 2.0 + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") Query setParameter(Parameter param, Date value, TemporalType temporalType); @@ -4331,7 +4365,10 @@ public interface Query { * @throws IllegalArgumentException if the parameter name does * not correspond to a parameter of the query or if * the value argument is of incorrect type + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") Query setParameter(String name, Calendar value, TemporalType temporalType); @@ -4344,7 +4381,10 @@ public interface Query { * @throws IllegalArgumentException if the parameter name does * not correspond to a parameter of the query or if * the value argument is of incorrect type + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") Query setParameter(String name, Date value, TemporalType temporalType); @@ -4369,7 +4409,10 @@ public interface Query { * @throws IllegalArgumentException if position does not * correspond to a positional parameter of the query or * if the value argument is of incorrect type + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") Query setParameter(int position, Calendar value, TemporalType temporalType); @@ -4382,7 +4425,10 @@ public interface Query { * @throws IllegalArgumentException if position does not * correspond to a positional parameter of the query or * if the value argument is of incorrect type + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") Query setParameter(int position, Date value, TemporalType temporalType); @@ -4555,6 +4601,40 @@ public interface Query { */ LockModeType getLockMode(); + /** + * Set the cache retrieval mode that is in effect during + * query execution. This cache retrieval mode overrides the + * cache retrieve mode in use by the entity manager. + * @param cacheRetrieveMode cache retrieval mode + * @return the same query instance + * @since 3.2 + */ + Query setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode); + + /** + * Set the cache storage mode that is in effect during + * query execution. This cache storage mode overrides the + * cache storage mode in use by the entity manager. + * @param cacheStoreMode cache storage mode + * @return the same query instance + * @since 3.2 + */ + Query setCacheStoreMode(CacheStoreMode cacheStoreMode); + + /** + * The cache retrieval mode that will be in effect during + * query execution. + * @since 3.2 + */ + CacheRetrieveMode getCacheRetrieveMode(); + + /** + * The cache storage mode that will be in effect during + * query execution. + * @since 3.2 + */ + CacheStoreMode getCacheStoreMode(); + /** * Return an object of the specified type to allow access to * the provider-specific API. If the provider's query @@ -4748,7 +4828,10 @@ public interface TypedQuery extends Query { * @return the same query instance * @throws IllegalArgumentException if the parameter does not * correspond to a parameter of the query + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") TypedQuery setParameter(Parameter param, Calendar value, TemporalType temporalType); @@ -4761,7 +4844,10 @@ public interface TypedQuery extends Query { * @return the same query instance * @throws IllegalArgumentException if the parameter does not * correspond to a parameter of the query + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") TypedQuery setParameter(Parameter param, Date value, TemporalType temporalType); @@ -4785,7 +4871,10 @@ public interface TypedQuery extends Query { * @throws IllegalArgumentException if the parameter name does * not correspond to a parameter of the query or if * the value argument is of incorrect type + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") TypedQuery setParameter(String name, Calendar value, TemporalType temporalType); @@ -4798,7 +4887,10 @@ public interface TypedQuery extends Query { * @throws IllegalArgumentException if the parameter name does * not correspond to a parameter of the query or if * the value argument is of incorrect type + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") TypedQuery setParameter(String name, Date value, TemporalType temporalType); @@ -4823,7 +4915,10 @@ public interface TypedQuery extends Query { * @throws IllegalArgumentException if position does not * correspond to a positional parameter of the query * or if the value argument is of incorrect type + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") TypedQuery setParameter(int position, Calendar value, TemporalType temporalType); @@ -4836,7 +4931,10 @@ public interface TypedQuery extends Query { * @throws IllegalArgumentException if position does not * correspond to a positional parameter of the query * or if the value argument is of incorrect type + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") TypedQuery setParameter(int position, Date value, TemporalType temporalType); @@ -4859,6 +4957,26 @@ public interface TypedQuery extends Query { */ TypedQuery setLockMode(LockModeType lockMode); + /** + * Set the cache retrieval mode that is in effect during + * query execution. This cache retrieval mode overrides the + * cache retrieve mode in use by the entity manager. + * @param cacheRetrieveMode cache retrieval mode + * @return the same query instance + * @since 3.2 + */ + TypedQuery setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode); + + /** + * Set the cache storage mode that is in effect during + * query execution. This cache storage mode overrides the + * cache storage mode in use by the entity manager. + * @param cacheStoreMode cache storage mode + * @return the same query instance + * @since 3.2 + */ + TypedQuery setCacheStoreMode(CacheStoreMode cacheStoreMode); + } ---- @@ -5156,7 +5274,10 @@ public interface StoredProcedureQuery extends Query { * @return the same query instance * @throws IllegalArgumentException if the parameter does not * correspond to a parameter of the query + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") StoredProcedureQuery setParameter(Parameter param, Calendar value, TemporalType temporalType); @@ -5169,7 +5290,10 @@ public interface StoredProcedureQuery extends Query { * @return the same query instance * @throws IllegalArgumentException if the parameter does not * correspond to a parameter of the query + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") StoredProcedureQuery setParameter(Parameter param, Date value, TemporalType temporalType); @@ -5194,7 +5318,10 @@ public interface StoredProcedureQuery extends Query { * @throws IllegalArgumentException if the parameter name does * not correspond to a parameter of the query or if the * value argument is of incorrect type + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") StoredProcedureQuery setParameter(String name, Calendar value, TemporalType temporalType); @@ -5208,7 +5335,10 @@ public interface StoredProcedureQuery extends Query { * @throws IllegalArgumentException if the parameter name does * not correspond to a parameter of the query or if the * value argument is of incorrect type + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") StoredProcedureQuery setParameter(String name, Date value, TemporalType temporalType); @@ -5234,7 +5364,10 @@ public interface StoredProcedureQuery extends Query { * @throws IllegalArgumentException if position does not * correspond to a positional parameter of the query or * if the value argument is of incorrect type + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") StoredProcedureQuery setParameter(int position, Calendar value, TemporalType temporalType); @@ -5248,7 +5381,10 @@ public interface StoredProcedureQuery extends Query { * @throws IllegalArgumentException if position does not * correspond to a positional parameter of the query or * if the value argument is of incorrect type + * @deprecated Newly-written code should use the date/time types + * defined in {@link java.time}. */ + @Deprecated(since = "3.2") StoredProcedureQuery setParameter(int position, Date value, TemporalType temporalType); @@ -5262,6 +5398,26 @@ public interface StoredProcedureQuery extends Query { */ StoredProcedureQuery setFlushMode(FlushModeType flushMode); + /** + * Set the cache retrieval mode that is in effect during + * query execution. This cache retrieval mode overrides the + * cache retrieve mode in use by the entity manager. + * @param cacheRetrieveMode cache retrieval mode + * @return the same query instance + * @since 3.2 + */ + StoredProcedureQuery setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode); + + /** + * Set the cache storage mode that is in effect during + * query execution. This cache storage mode overrides the + * cache storage mode in use by the entity manager. + * @param cacheStoreMode cache storage mode + * @return the same query instance + * @since 3.2 + */ + StoredProcedureQuery setCacheStoreMode(CacheStoreMode cacheStoreMode); + /** * Register a positional parameter. * All parameters must be registered. From ca823403eff93f1f776ba66197d120509ce2fe8a Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 11 Aug 2023 20:07:04 +0200 Subject: [PATCH 4/6] add RefreshOption and overload EM.refresh() see #399 --- .../jakarta/persistence/CacheStoreMode.java | 2 +- .../jakarta/persistence/EntityManager.java | 49 ++++++++++++++++++- .../jakarta/persistence/LockModeType.java | 2 +- .../persistence/PessimisticLockScope.java | 2 +- .../jakarta/persistence/RefreshOption.java | 38 ++++++++++++++ .../java/jakarta/persistence/Timeout.java | 2 +- .../main/asciidoc/ch03-entity-operations.adoc | 47 +++++++++++++++++- 7 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 api/src/main/java/jakarta/persistence/RefreshOption.java diff --git a/api/src/main/java/jakarta/persistence/CacheStoreMode.java b/api/src/main/java/jakarta/persistence/CacheStoreMode.java index 6761cd9a..5d05436b 100644 --- a/api/src/main/java/jakarta/persistence/CacheStoreMode.java +++ b/api/src/main/java/jakarta/persistence/CacheStoreMode.java @@ -27,7 +27,7 @@ * * @since 2.0 */ -public enum CacheStoreMode implements FindOption { +public enum CacheStoreMode implements FindOption, RefreshOption { /** * Insert entity data into cache when read from database diff --git a/api/src/main/java/jakarta/persistence/EntityManager.java b/api/src/main/java/jakarta/persistence/EntityManager.java index 93627f10..9416ff34 100644 --- a/api/src/main/java/jakarta/persistence/EntityManager.java +++ b/api/src/main/java/jakarta/persistence/EntityManager.java @@ -513,7 +513,7 @@ public void lock(Object entity, LockModeType lockMode, * @since 2.0 */ public void refresh(Object entity, - Map properties); + Map properties); /** * Refresh the state of the instance from the database, @@ -597,7 +597,52 @@ public void refresh(Object entity, */ public void refresh(Object entity, LockModeType lockMode, Map properties); - + + /** + * Refresh the state of the given entity instance from the + * database, using the specified {@linkplain RefreshOption options}, + * overwriting changes made to the entity, if any. If the supplied + * options include a {@link LockModeType}, lock the given entity with + * respect to the specified lock type. + *

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 RefreshOption} 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 hint may + * or may not be observed. + * @param entity entity instance + * @param options standard and vendor-specific options + * @throws IllegalArgumentException if the instance is not an entity + * or the entity is not managed + * @throws TransactionRequiredException if invoked on a + * container-managed entity manager of type + * PersistenceContextType.TRANSACTION when there + * is no transaction; if invoked on an extended entity manager + * when there is no transaction and a lock mode other than + * NONE has been specified; or if invoked on an + * extended entity manager that has not been joined to the + * current transaction and a lock mode other than + * NONE has been specified + * @throws EntityNotFoundException if the entity no longer exists in + * the database + * @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 refresh(Object entity, + RefreshOption... options); + /** * Clear the persistence context, causing all managed * entities to become detached. Changes made to entities that diff --git a/api/src/main/java/jakarta/persistence/LockModeType.java b/api/src/main/java/jakarta/persistence/LockModeType.java index 6eac8bcc..903ee9b5 100644 --- a/api/src/main/java/jakarta/persistence/LockModeType.java +++ b/api/src/main/java/jakarta/persistence/LockModeType.java @@ -126,7 +126,7 @@ * @since 1.0 * */ -public enum LockModeType implements FindOption { +public enum LockModeType implements FindOption, RefreshOption { /** * Synonymous with OPTIMISTIC. * OPTIMISTIC is to be preferred for new diff --git a/api/src/main/java/jakarta/persistence/PessimisticLockScope.java b/api/src/main/java/jakarta/persistence/PessimisticLockScope.java index 91bde605..e1541ff1 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 { +public enum PessimisticLockScope implements FindOption, RefreshOption { /** * This value defines the default behavior for pessimistic locking. diff --git a/api/src/main/java/jakarta/persistence/RefreshOption.java b/api/src/main/java/jakarta/persistence/RefreshOption.java new file mode 100644 index 00000000..0cc866e0 --- /dev/null +++ b/api/src/main/java/jakarta/persistence/RefreshOption.java @@ -0,0 +1,38 @@ +/* + * 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#refresh}. + * Built-in options control {@linkplain LockModeType locking}, + * {@linkplain CacheStoreMode cache interaction}, 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 CacheStoreMode + * @see Timeout + * + * @see EntityManager#refresh(Object, RefreshOption...) + * + * @since 3.2 + */ +public interface RefreshOption { +} diff --git a/api/src/main/java/jakarta/persistence/Timeout.java b/api/src/main/java/jakarta/persistence/Timeout.java index b0761d80..060c2230 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 { +public class Timeout implements FindOption, RefreshOption { 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 29d45cd5..b0683ff7 100644 --- a/spec/src/main/asciidoc/ch03-entity-operations.adoc +++ b/spec/src/main/asciidoc/ch03-entity-operations.adoc @@ -546,7 +546,7 @@ public interface EntityManager extends AutoCloseable { * @since 2.0 */ public void refresh(Object entity, - Map properties); + Map properties); /** * Refresh the state of the instance from the database, @@ -631,6 +631,51 @@ public interface EntityManager extends AutoCloseable { public void refresh(Object entity, LockModeType lockMode, Map properties); + /** + * Refresh the state of the given entity instance from the + * database, using the specified {@linkplain RefreshOption options}, + * overwriting changes made to the entity, if any. If the supplied + * options include a {@link LockModeType}, lock the given entity with + * respect to the specified lock type. + *

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 RefreshOption} 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 hint may + * or may not be observed. + * @param entity entity instance + * @param options standard and vendor-specific options + * @throws IllegalArgumentException if the instance is not an entity + * or the entity is not managed + * @throws TransactionRequiredException if invoked on a + * container-managed entity manager of type + * PersistenceContextType.TRANSACTION when there + * is no transaction; if invoked on an extended entity manager + * when there is no transaction and a lock mode other than + * NONE has been specified; or if invoked on an + * extended entity manager that has not been joined to the + * current transaction and a lock mode other than + * NONE has been specified + * @throws EntityNotFoundException if the entity no longer exists in + * the database + * @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 refresh(Object entity, + RefreshOption... options); + /** * Clear the persistence context, causing all managed * entities to become detached. Changes made to entities that From 8afd89ff94e65cdd56df1863f3874423bcfddba3 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 11 Aug 2023 20:15:35 +0200 Subject: [PATCH 5/6] add LockOption and overload EM.lock() see #399 --- .../jakarta/persistence/EntityManager.java | 48 +++++++++++++++++++ .../java/jakarta/persistence/LockOption.java | 36 ++++++++++++++ .../persistence/PessimisticLockScope.java | 2 +- .../java/jakarta/persistence/Timeout.java | 2 +- .../main/asciidoc/ch03-entity-operations.adoc | 48 +++++++++++++++++++ 5 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 api/src/main/java/jakarta/persistence/LockOption.java 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 060c2230..ecbd8e67 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. From 1cc4d0f262fbaa77046fbb99d22323f21eedba19 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Sat, 19 Aug 2023 13:33:18 +0200 Subject: [PATCH 6/6] add Query.setTimeout() see #383 --- api/src/main/java/jakarta/persistence/Query.java | 14 ++++++++++++++ .../jakarta/persistence/StoredProcedureQuery.java | 8 ++++++++ .../main/java/jakarta/persistence/TypedQuery.java | 7 +++++++ 3 files changed, 29 insertions(+) diff --git a/api/src/main/java/jakarta/persistence/Query.java b/api/src/main/java/jakarta/persistence/Query.java index 3748e745..317ee80b 100644 --- a/api/src/main/java/jakarta/persistence/Query.java +++ b/api/src/main/java/jakarta/persistence/Query.java @@ -546,6 +546,20 @@ Query setParameter(int position, Date value, */ CacheStoreMode getCacheStoreMode(); + /** + * Set the query timeout. + * @param timeout the timeout, or null to indicate no timeout + * @return the same query instance + * @since 3.2 + */ + Query setTimeout(Integer timeout); + + /** + * The query timeout. + * @since 3.2 + */ + Integer getTimeout(); + /** * Return an object of the specified type to allow access to * the provider-specific API. If the provider's query diff --git a/api/src/main/java/jakarta/persistence/StoredProcedureQuery.java b/api/src/main/java/jakarta/persistence/StoredProcedureQuery.java index 7c814d8d..8a99851b 100644 --- a/api/src/main/java/jakarta/persistence/StoredProcedureQuery.java +++ b/api/src/main/java/jakarta/persistence/StoredProcedureQuery.java @@ -281,6 +281,14 @@ StoredProcedureQuery setParameter(int position, */ StoredProcedureQuery setCacheStoreMode(CacheStoreMode cacheStoreMode); + /** + * Set the query timeout. + * @param timeout the timeout, or null to indicate no timeout + * @return the same query instance + * @since 3.2 + */ + StoredProcedureQuery setTimeout(Integer timeout); + /** * Register a positional parameter. * All parameters must be registered. diff --git a/api/src/main/java/jakarta/persistence/TypedQuery.java b/api/src/main/java/jakarta/persistence/TypedQuery.java index 51bb93e2..6b15a0c6 100644 --- a/api/src/main/java/jakarta/persistence/TypedQuery.java +++ b/api/src/main/java/jakarta/persistence/TypedQuery.java @@ -336,4 +336,11 @@ TypedQuery setParameter(int position, Date value, */ TypedQuery setCacheStoreMode(CacheStoreMode cacheStoreMode); + /** + * Set the query timeout. + * @param timeout the timeout, or null to indicate no timeout + * @return the same query instance + * @since 3.2 + */ + TypedQuery setTimeout(Integer timeout); }