From 9af565510064635dba7e48087ab4e8f5ef439f0d Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 7 Dec 2017 14:24:06 +0000 Subject: [PATCH] HHH-12148 - Add setting indicating if the value stored in the table used by the @TableGenerator is the last value used or the next value to be used --- .../userguide/appendices/Configurations.adoc | 3 ++ .../org/hibernate/cfg/AvailableSettings.java | 9 ++++ .../java/org/hibernate/cfg/BinderHelper.java | 3 +- .../hibernate/id/enhanced/TableGenerator.java | 44 ++++++++++++++++--- migration-guide.adoc | 8 ++++ 5 files changed, 60 insertions(+), 7 deletions(-) diff --git a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc index 10dbcdf585..f60d36db9b 100644 --- a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc +++ b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc @@ -186,6 +186,9 @@ If true, generated identifier properties are reset to default values when object `*hibernate.id.optimizer.pooled.preferred*` (e.g. `none`, `hilo`, `legacy-hilo`, `pooled` (default value), `pooled-lo`, `pooled-lotl` or a fully-qualified name of the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/id/enhanced/Optimizer.html[`Optimizer`] implementation):: When a generator specified an increment-size and an optimizer was not explicitly specified, which of the _pooled_ optimizers should be preferred? +`*hibernate.id.generator.stored_last_used*` (e.g. `true` (default value) or `false`):: +If true, the value stored in the table used by the `@TableGenerator` is the last value used, if false the value is the next value to be used. + ==== Quoting options `*hibernate.globally_quoted_identifiers*` (e.g. `true` or `false` (default value)):: diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index 9814c5f5a7..3abbd5d8df 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -1790,4 +1790,13 @@ public interface AvailableSettings { * @see JpaCompliance#isJpaClosedComplianceEnabled() */ String JPA_CLOSED_COMPLIANCE = "hibernate.jpa.compliance.closed"; + + /** + * True/False setting indicating if the value stored in the table used by the {@link javax.persistence.TableGenerator} + * is the last value generated or the next value to be used. + * + * The default value is true. + * + */ + String TABLE_GENERATOR_STORE_LAST_USED = "hibernate.id.generator.stored_last_used"; } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java b/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java index 3091308b61..ea22cbbcf5 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java @@ -812,9 +812,10 @@ public class BinderHelper { public String table() { return ""; } + @Override public int initialValue() { - return 1; + return 0; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java index cd27fda198..48c63bf532 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java @@ -22,6 +22,7 @@ import org.hibernate.LockOptions; import org.hibernate.MappingException; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.Database; +import org.hibernate.boot.model.relational.InitCommand; import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.QualifiedName; import org.hibernate.boot.model.relational.QualifiedNameParser; @@ -226,6 +227,8 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab */ public static final String OPT_PARAM = "optimizer"; + private boolean storeLastUsedValue; + private Type identifierType; @@ -355,6 +358,8 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab @Override public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException { + storeLastUsedValue = serviceRegistry.getService( ConfigurationService.class ) + .getSetting( AvailableSettings.TABLE_GENERATOR_STORE_LAST_USED, StandardConverters.BOOLEAN, true ); identifierType = type; final JdbcEnvironment jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class ); @@ -374,11 +379,12 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab params, OptimizerFactory.determineImplicitOptimizerName( incrementSize, params ) ); + int optimizerInitialValue = ConfigurationHelper.getInt( INITIAL_PARAM, params, -1 ); optimizer = OptimizerFactory.buildOptimizer( optimizationStrategy, identifierType.getReturnedClass(), incrementSize, - ConfigurationHelper.getInt( INITIAL_PARAM, params, -1 ) + optimizerInitialValue ); } @@ -542,6 +548,14 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab return "insert into " + renderedTableName + " (" + segmentColumnName + ", " + valueColumnName + ") " + " values (?,?)"; } + protected InitCommand generateInsertInitCommand() { + int value = initialValue; + if ( storeLastUsedValue ) { + value = initialValue - 1; + } + return new InitCommand( "insert into " + renderedTableName + "(" + segmentColumnName + ", " + valueColumnName + ")" + " values ('" + segmentValue + "'," + ( value ) + ")" ); + } + private IntegralDataTypeHolder makeValue() { return IdentifierGeneratorHelper.getIntegralDataTypeHolder( identifierType.getReturnedClass() ); } @@ -574,7 +588,14 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab selectPS.setString( 1, segmentValue ); final ResultSet selectRS = executeQuery( selectPS, statsCollector ); if ( !selectRS.next() ) { - value.initialize( initialValue ); + long initializationValue; + if ( storeLastUsedValue ) { + initializationValue = initialValue - 1; + } + else { + initializationValue = initialValue; + } + value.initialize( initializationValue ); try (PreparedStatement insertPS = prepareStatement( connection, @@ -589,7 +610,14 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab } } else { - value.initialize( selectRS, 1 ); + int defaultValue; + if ( storeLastUsedValue ) { + defaultValue = 0; + } + else { + defaultValue = 1; + } + value.initialize( selectRS, defaultValue ); } selectRS.close(); } @@ -625,8 +653,12 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab while ( rows == 0 ); accessCount++; - - return value; + if ( storeLastUsedValue ) { + return value.increment(); + } + else { + return value; + } } }, true @@ -734,10 +766,10 @@ public class TableGenerator implements PersistentIdentifierGenerator, Configurab table.getQualifiedTableName(), dialect ); + table.addInitCommand( generateInsertInitCommand() ); this.selectQuery = buildSelectQuery( dialect ); this.updateQuery = buildUpdateQuery(); this.insertQuery = buildInsertQuery(); - } } diff --git a/migration-guide.adoc b/migration-guide.adoc index e238ccb43b..afac2a9baa 100644 --- a/migration-guide.adoc +++ b/migration-guide.adoc @@ -27,3 +27,11 @@ instead of zero-bade parameter binding to be consistent with JPA. That can temp reverted by setting the `hibernate.query.sql.jdbc_style_params_base` setting to `true` which reverts to expecting zero-based binding. +== Change in the `@TableGenerator` stored value + +In order to be compliant with JPA specifications, the value stored by Hibernate 5.3 in the Table used by the `javax.persistence.TableGenerator` is the last value generated. +Previous versions of Hibernate instead stored the next value to be used. + +For backward compatibility a new setting, `hibernate.id.generator.stored_last_used`, has been introduced that gives the opportunity to fall back to the old Hibernate behaviour. +Existing applications migrating to 5.3 and using @TableGenerator have to set `hibernate.id.generator.stored_last_used` to `false`. +