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

This commit is contained in:
Andrea Boriero 2017-12-07 14:24:06 +00:00 committed by Steve Ebersole
parent 2b7c2c883c
commit 9af5655100
5 changed files with 60 additions and 7 deletions

View File

@ -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))::

View File

@ -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";
}

View File

@ -812,9 +812,10 @@ public class BinderHelper {
public String table() {
return "";
}
@Override
public int initialValue() {
return 1;
return 0;
}
@Override

View File

@ -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();
}
}

View File

@ -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`.