diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/NamedNativeQuery.java b/hibernate-core/src/main/java/org/hibernate/annotations/NamedNativeQuery.java index 865fab3a9b..a56139839a 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/NamedNativeQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/NamedNativeQuery.java @@ -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 {}; diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/NamedQuery.java b/hibernate-core/src/main/java/org/hibernate/annotations/NamedQuery.java index bc9e152a2b..b6e7656b2b 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/NamedQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/NamedQuery.java @@ -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; diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/Synchronize.java b/hibernate-core/src/main/java/org/hibernate/annotations/Synchronize.java index a028652505..d4ef5942a7 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/Synchronize.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/Synchronize.java @@ -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. *

- * 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. + *

+ * This annotation might be necessary if: + *

+ *

+ * 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; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java index 68b6cf569b..6c24c4c388 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EntityBinder.java @@ -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 diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/HibernateHints.java b/hibernate-core/src/main/java/org/hibernate/jpa/HibernateHints.java index a26c37dade..c951c11978 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/HibernateHints.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/HibernateHints.java @@ -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. *

- * 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}. *

- * 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. *

- * 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. - *

- * 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. *

- * Passed value can be any of: