HHH-16079 rewrite javadoc relating to query spaces + add @Synchronize(logical=false)

This commit is contained in:
Gavin 2023-01-22 12:27:58 +01:00 committed by Gavin King
parent 75f3f699b5
commit 662594fd5f
6 changed files with 133 additions and 73 deletions

View File

@ -156,10 +156,12 @@ public @interface NamedNativeQuery {
boolean readOnly() default false;
/**
* The query spaces involved in this query.
* The {@linkplain org.hibernate.query.SynchronizeableQuery query spaces}
* involved in this query.
*
* @see org.hibernate.query.SynchronizeableQuery
* @see org.hibernate.jpa.HibernateHints#HINT_NATIVE_SPACES
* @see Synchronize
*/
String[] querySpaces() default {};

View File

@ -86,7 +86,7 @@ public @interface NamedQuery {
*
* @see org.hibernate.query.CommonQueryContract#setTimeout(int)
* @see org.hibernate.jpa.HibernateHints#HINT_TIMEOUT
* @see import org.hibernate.jpa.SpecHints#HINT_SPEC_QUERY_TIMEOUT
* @see org.hibernate.jpa.SpecHints#HINT_SPEC_QUERY_TIMEOUT
*/
int timeout() default -1;

View File

@ -13,22 +13,47 @@ import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Specifies the tables that hold state mapped by the annotated derived
* entity, ensuring that auto-flush happens correctly and that queries
* against the derived entity do not return stale data.
* Specifies the tables that hold state mapped by the annotated entity.
* <p>
* This annotation may be used in combination with {@link Subselect}, or
* when an entity maps a database view.
* If Hibernate is not aware of that a certain table holds state mapped
* by an entity class, then {@linkplain org.hibernate.FlushMode#AUTO
* auto-flush} might not occur when it should, and queries against the
* entity might return stale data.
* <p>
* This annotation might be necessary if:
* <ul>
* <li>the entity maps a database view,
* <li>the entity is persisted using handwritten SQL, that is, using
* {@link SQLSelect @SQLSelect} and friends.
* <li>the entity is mapped using {@link Subselect @Subselect}.
* </ul>
* <p>
* By default, the table names specified by this annotation are interpreted
* as {@linkplain org.hibernate.boot.model.naming.PhysicalNamingStrategy
* logical names}, and are processed by
* {@link org.hibernate.boot.model.naming.PhysicalNamingStrategy#toPhysicalTableName}.
* But if {@link #logical logical=false}, the table names will be treated
* as physical names, and will not be processed by the naming strategy.
*
* @author Sharath Reddy
*
* @see org.hibernate.query.SynchronizeableQuery
*/
@Target(TYPE)
@Retention(RUNTIME)
public @interface Synchronize {
/**
* Names of tables that hold state mapped by the derived entity.
* Names of tables that hold state mapped by the annotated entity.
* Updates to these tables must be flushed to the database before
* the derived entity is queried.
* execution of any query which refers to the annotated entity.
*/
String[] value();
/**
* Specifies whether the table names given by {@link #value}
* should be interpreted as logical or physical names.
*
* @return {@code true} if they are logical names
*/
boolean logical() default true;
}

View File

@ -1336,17 +1336,23 @@ public class EntityBinder {
private void bindSynchronize() {
if ( annotatedClass.isAnnotationPresent( Synchronize.class ) ) {
final JdbcEnvironment jdbcEnvironment = context.getMetadataCollector().getDatabase().getJdbcEnvironment();
for ( String table : annotatedClass.getAnnotation(Synchronize.class).value() ) {
persistentClass.addSynchronizedTable(
context.getBuildingOptions().getPhysicalNamingStrategy().toPhysicalTableName(
jdbcEnvironment.getIdentifierHelper().toIdentifier( table ),
jdbcEnvironment
).render( jdbcEnvironment.getDialect() )
);
final Synchronize synchronize = annotatedClass.getAnnotation(Synchronize.class);
for ( String table : synchronize.value() ) {
String physicalName = synchronize.logical() ? toPhysicalName( jdbcEnvironment, table ) : table;
persistentClass.addSynchronizedTable( physicalName );
}
}
}
private String toPhysicalName(JdbcEnvironment jdbcEnvironment, String logicalName) {
return context.getBuildingOptions().getPhysicalNamingStrategy()
.toPhysicalTableName(
jdbcEnvironment.getIdentifierHelper().toIdentifier( logicalName ),
jdbcEnvironment
)
.render( jdbcEnvironment.getDialect() );
}
@SuppressWarnings({"rawtypes", "unchecked"})
private void bindCustomPersister() {
//set persister if needed

View File

@ -6,32 +6,32 @@
*/
package org.hibernate.jpa;
import org.hibernate.FlushMode;
import org.hibernate.query.Query;
/**
* List of Hibernate-specific (extension) hints available to query,
* load and lock scenarios.
* load, and lock scenarios.
* <p>
* Some hints are only effective in certain scenarios, which is noted on
* each constant's documentation.
* Some hints are only effective in certain scenarios, which is noted
* on each constant's documentation.
*
* @author Steve Ebersole
*/
public interface HibernateHints {
/**
* Hint for specifying the {@link org.hibernate.FlushMode}
* to apply to an EntityManager or a Query
* Hint for specifying the {@link org.hibernate.FlushMode} to
* apply to an {@link jakarta.persistence.EntityManager} or
* {@link jakarta.persistence.Query}.
*
* @see Query#setHibernateFlushMode
* @see org.hibernate.query.Query#setHibernateFlushMode
* @see org.hibernate.Session#setHibernateFlushMode
*/
String HINT_FLUSH_MODE = "org.hibernate.flushMode";
/**
* Hint for specifying a Query timeout, in seconds.
* Hint for specifying a
* {@linkplain org.hibernate.query.CommonQueryContract#setTimeout
* query timeout}, in seconds.
*
* @see org.hibernate.query.Query#setTimeout
* @see org.hibernate.query.CommonQueryContract#setTimeout
* @see java.sql.Statement#setQueryTimeout
* @see SpecHints#HINT_SPEC_QUERY_TIMEOUT
*/
@ -40,67 +40,69 @@ public interface HibernateHints {
/**
* Hint for specifying that objects loaded into the persistence
* context as a result of a query should be associated with the
* persistence context as read-only.
* persistence context in
* {@linkplain org.hibernate.query.SelectionQuery#setReadOnly
* read-only mode}.
*
* @see Query#setReadOnly
* @see org.hibernate.query.SelectionQuery#setReadOnly
* @see org.hibernate.Session#setDefaultReadOnly
*/
String HINT_READ_ONLY = "org.hibernate.readOnly";
/**
* Hint for specifying a fetch size to be applied to the
* JDBC statement.
* Hint for specifying a JDBC fetch size to be applied to the
* statement.
*
* @see Query#setFetchSize
* @see org.hibernate.query.SelectionQuery#setFetchSize
* @see java.sql.Statement#setFetchSize
*/
String HINT_FETCH_SIZE = "org.hibernate.fetchSize";
/**
* Hint for specifying whether results from a query should
* be stored in the query cache
* Hint for specifying whether results from a query should be
* stored in the query cache.
*
* @see Query#setCacheable
* @see org.hibernate.query.SelectionQuery#setCacheable
*/
String HINT_CACHEABLE = "org.hibernate.cacheable";
/**
* Hint for specifying the region of the query cache into which
* the results should be stored
* the results should be stored.
*
* @implSpec No effect unless {@link #HINT_CACHEABLE} is set to {@code true}
*
* @see Query#setCacheRegion
* @see org.hibernate.query.SelectionQuery#setCacheRegion
*/
String HINT_CACHE_REGION = "org.hibernate.cacheRegion";
/**
* Hint for specifying the {@link org.hibernate.CacheMode} to use
* Hint for specifying the {@link org.hibernate.CacheMode} to use.
*
* @implSpec No effect unless {@link #HINT_CACHEABLE} is set to {@code true}
*
* @see Query#setCacheMode
* @see org.hibernate.query.SelectionQuery#setCacheMode
*/
String HINT_CACHE_MODE = "org.hibernate.cacheMode";
/**
* Hint for specifying a database comment to be applied to
* the SQL sent to the database.
* Hint for specifying a database comment to be appended to the
* SQL statement sent to the database.
*
* @implSpec Not valid for {@link org.hibernate.procedure.ProcedureCall}
* nor {@link jakarta.persistence.StoredProcedureQuery} scenarios
* @implSpec Not valid for {@link org.hibernate.procedure.ProcedureCall},
* nor for {@link jakarta.persistence.StoredProcedureQuery}.
*
* @see Query#setComment
* @see org.hibernate.query.SelectionQuery#setComment
*/
String HINT_COMMENT = "org.hibernate.comment";
/**
* Hint to enable/disable the follow-on-locking mechanism provided by
* {@link org.hibernate.dialect.Dialect#useFollowOnLocking}.
* Hint to enable or disable the follow-on locking mechanism provided
* by {@link org.hibernate.dialect.Dialect#useFollowOnLocking}.
* <p>
* A value of {@code true} enables follow-on-locking, whereas a value of
* {@code false} disables it. If the value is {@code null}, the
* {@code Dialect}'s default strategy is used.
* A value of {@code true} enables follow-on-locking, whereas a value
* of {@code false} disables it. If the value is {@code null}, the
* dialect itself will determine whether follow-on locking is used.
*
* @see org.hibernate.LockOptions#setFollowOnLocking(Boolean)
*
@ -112,38 +114,38 @@ public interface HibernateHints {
* Hint for specifying the lock mode to apply to the results of a
* native query.
* <p>
* While Hibernate supports applying lock-mode to a native-query, the
* JPA specification requires that {@link jakarta.persistence.Query#setLockMode}
* throw an {@link IllegalStateException} if called for a native query.
* <p>
* Accepts a {@link jakarta.persistence.LockModeType} or a {@link org.hibernate.LockMode}
* Accepts either a {@link jakarta.persistence.LockModeType} or a
* {@link org.hibernate.LockMode}.
*
* @apiNote While Hibernate supports applying a lock mode to a
* native query, the JPA specification requires that
* {@link jakarta.persistence.Query#setLockMode} throw
* an {@link IllegalStateException} in this scenario.
*/
String HINT_NATIVE_LOCK_MODE = "org.hibernate.lockMode";
/**
* Hint for specifying query spaces to be applied to a native query.
* Hint for specifying the
* {@link org.hibernate.query.SynchronizeableQuery query spaces}
* that affect the results of a native query.
* <p>
* Passed value can be any of:<ul>
* <li>List of the spaces</li>
* <li>array of the spaces</li>
* <li>String as "whitespace"-separated list of the spaces</li>
* Passed value can be any of:
* <ul>
* <li>a {@link org.hibernate.mapping.List} of the spaces,
* <li>an array of the spaces, or
* <li>a string with a whitespace-separated list of the spaces.
* </ul>
* <p>
* Note that the passed space need not match any real spaces/tables in
* the underlying query. This can be used to completely circumvent
* the auto-flush checks as well as any cache invalidation that might
* occur as part of a flush. See {@link org.hibernate.query.SynchronizeableQuery}
* and {@link FlushMode#MANUAL} for more information.
*
* @see org.hibernate.query.SynchronizeableQuery
* @see #HINT_FLUSH_MODE
* @see org.hibernate.annotations.NamedNativeQuery#querySpaces
*/
String HINT_NATIVE_SPACES = "org.hibernate.query.native.spaces";
/**
* Whether to treat a {@link org.hibernate.procedure.ProcedureCall}
* or {@link jakarta.persistence.StoredProcedureQuery} as a call
* to a function rather than a call to a procedure
* to a function rather than a call to a procedure.
*/
String HINT_CALLABLE_FUNCTION = "org.hibernate.callableFunction";
}

View File

@ -12,16 +12,41 @@ import java.util.Collection;
import org.hibernate.MappingException;
/**
* A unifying interface for queries which can define tables (query spaces) to synchronize on.
* Represents the abstract notion of a query whose results are affected by the data stored
* in a given set of named <em>query spaces</em>. A query space is usually, but not always,
* a relational database table, in which case the name of the space is simply the table name.
* <p>
* These query spaces affect the process of auto-flushing by determining which entities will be
* processed by auto-flush based on the table to which those entities are mapped and which are
* determined to have pending state changes.
* Each {@linkplain jakarta.persistence.Entity entity type} is understood to store its state
* in one or more query spaces. Usually, the query spaces are automatically determined by
* the mapping, but sometimes they must be specified explicitly using
* {@link org.hibernate.annotations.Synchronize @Synchronize}.
* <p>
* In a similar manner, these query spaces also affect how query result caching can recognize
* invalidated results.
* Query spaces mediate the interaction between query execution and synchronization of
* in-memory state with the database:
* <ul>
* <li>
* When {@linkplain org.hibernate.FlushMode#AUTO auto-flush} is enabled, in-memory changes
* to every dirty entity whose state belongs to any query space which affects a given query
* must be flushed before the query is executed.
* <li>
* Conversely, when changes to an entity whose state is stored in a given query space are
* flushed to the database, every {@linkplain SelectionQuery#setCacheable cached query
* result set} for a query affected by that query space must be immediately invalidated.
* </ul>
* <p>
* Typically, query spaces are independent (non-overlapping), and Hibernate always treats
* them as such. Overlapping or hierarchical query spaces are in principle meaningful, but
* any such relationship between query spaces is the responsibility of the client.
* <p>
* A query space name is not always a table name. In principle, it's permitted to be any
* arbitrary string which uniquely identifies an abstract location where state is stored
* persistently. It's even possible that the data in a single table is segmented in such
* a way that the table is effectively the union of multiple independent query spaces.
*
* @author Steve Ebersole
*
* @see org.hibernate.annotations.Synchronize
* @see org.hibernate.jpa.HibernateHints#HINT_NATIVE_SPACES
*/
public interface SynchronizeableQuery {
/**