下面列出了怎么用org.hibernate.type.VersionType的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* Create an initial optimistic locking value according the {@link VersionType}
* contract for the version property <b>if required</b> and inject it into
* the snapshot state.
*
* @param fields The current snapshot state
* @param versionProperty The index of the version property
* @param versionType The version type
* @param session The originating session
* @return True if we injected a new version value into the fields array; false
* otherwise.
*/
public static boolean seedVersion(
Object[] fields,
int versionProperty,
VersionType versionType,
SharedSessionContractImplementor session) {
final Object initialVersion = fields[versionProperty];
if (
initialVersion==null ||
// This next bit is to allow for both unsaved-value="negative"
// and for "older" behavior where version number did not get
// seeded if it was already set in the object
// TODO: shift it into unsaved-value strategy
( (initialVersion instanceof Number) && ( (Number) initialVersion ).longValue()<0 )
) {
fields[versionProperty] = seed( versionType, session );
return true;
}
LOG.tracev( "Using initial version: {0}", initialVersion );
return false;
}
/**
* Create an initial optimisitc locking value according the {@link VersionType}
* contract for the version property <b>if required</b> and inject it into
* the snapshot state.
*
* @param fields The current snapshot state
* @param versionProperty The index of the version property
* @param versionType The version type
* @param session The orginating session
* @return True if we injected a new version value into the fields array; false
* otherwise.
*/
public static boolean seedVersion(
Object[] fields,
int versionProperty,
VersionType versionType,
SessionImplementor session) {
Object initialVersion = fields[versionProperty];
if (
initialVersion==null ||
// This next bit is to allow for both unsaved-value="negative"
// and for "older" behavior where version number did not get
// seeded if it was already set in the object
// TODO: shift it into unsaved-value strategy
( (initialVersion instanceof Number) && ( (Number) initialVersion ).longValue()<0 )
) {
fields[versionProperty] = seed( versionType, session );
return true;
}
else {
if ( log.isTraceEnabled() ) {
log.trace( "using initial version: " + initialVersion );
}
return false;
}
}
/**
* Check the version of the object in the <tt>ResultSet</tt> against
* the object version in the session cache, throwing an exception
* if the version numbers are different
*/
private void checkVersion(
final int i,
final Loadable persister,
final Serializable id,
final Object entity,
final ResultSet rs,
final SharedSessionContractImplementor session) throws HibernateException, SQLException {
Object version = session.getPersistenceContext().getEntry( entity ).getVersion();
if ( version != null ) { //null version means the object is in the process of being loaded somewhere else in the ResultSet
final VersionType versionType = persister.getVersionType();
final Object currentVersion = versionType.nullSafeGet(
rs,
getEntityAliases()[i].getSuffixedVersionAliases(),
session,
null
);
if ( !versionType.isEqual( version, currentVersion ) ) {
if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
session.getFactory().getStatistics().optimisticFailure( persister.getEntityName() );
}
throw new StaleObjectStateException( persister.getEntityName(), id );
}
}
}
private void checkVersion(
SharedSessionContractImplementor session,
ResultSet resultSet,
EntityPersister persister,
EntityAliases entityAliases,
EntityKey entityKey,
Object entityInstance) {
final Object version = session.getPersistenceContext().getEntry( entityInstance ).getVersion();
if ( version != null ) {
//null version means the object is in the process of being loaded somewhere else in the ResultSet
VersionType versionType = persister.getVersionType();
final Object currentVersion;
try {
currentVersion = versionType.nullSafeGet(
resultSet,
entityAliases.getSuffixedVersionAliases(),
session,
null
);
}
catch (SQLException e) {
throw session.getFactory().getServiceRegistry().getService( JdbcServices.class ).getSqlExceptionHelper().convert(
e,
"Could not read version value from result set"
);
}
if ( !versionType.isEqual( version, currentVersion ) ) {
if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
session.getFactory().getStatistics().optimisticFailure( persister.getEntityName() );
}
throw new StaleObjectStateException( persister.getEntityName(), entityKey.getIdentifier() );
}
}
}
/**
* Generates a VersionProperty representation for an entity mapping given its
* version mapping Property.
*
* @param property The version mapping Property.
* @param lazyAvailable Is property lazy loading currently available.
*
* @return The appropriate VersionProperty definition.
*/
public static VersionProperty buildVersionProperty(
EntityPersister persister,
SessionFactoryImplementor sessionFactory,
int attributeNumber,
Property property,
boolean lazyAvailable) {
String mappedUnsavedValue = ( (KeyValue) property.getValue() ).getNullValue();
VersionValue unsavedValue = UnsavedValueFactory.getUnsavedVersionValue(
mappedUnsavedValue,
getGetter( property ),
(VersionType) property.getType(),
getConstructor( property.getPersistentClass() )
);
boolean lazy = lazyAvailable && property.isLazy();
return new VersionProperty(
persister,
sessionFactory,
attributeNumber,
property.getName(),
property.getValue().getType(),
new BaselineAttributeInformation.Builder()
.setLazy( lazy )
.setInsertable( property.isInsertable() )
.setUpdateable( property.isUpdateable() )
.setValueGenerationStrategy( property.getValueGenerationStrategy() )
.setNullable( property.isOptional() )
.setDirtyCheckable( property.isUpdateable() && !lazy )
.setVersionable( property.isOptimisticLocked() )
.setCascadeStyle( property.getCascadeStyle() )
.createInformation(),
unsavedValue
);
}
/**
* Generate the next increment in the optimistic locking value according
* the {@link VersionType} contract for the version property.
*
* @param version The current version
* @param versionType The version type
* @param session The originating session
* @return The incremented optimistic locking value.
*/
@SuppressWarnings("unchecked")
public static Object increment(Object version, VersionType versionType, SharedSessionContractImplementor session) {
final Object next = versionType.next( version, session );
if ( LOG.isTraceEnabled() ) {
LOG.tracef(
"Incrementing: %s to %s",
versionType.toLoggableString( version, session.getFactory() ),
versionType.toLoggableString( next, session.getFactory() )
);
}
return next;
}
/**
* Return an IdentifierValue for the specified unsaved-value. If none is specified,
* guess the unsaved value by instantiating a test instance of the class and
* reading it's version property value, or if that is not possible, using the java default
* value for the type
*
* @param versionUnsavedValue The mapping defined unsaved value
* @param versionGetter The version attribute getter
* @param versionType The mapping type for the version
* @param constructor The constructor for the entity
*
* @return The appropriate VersionValue
*/
public static VersionValue getUnsavedVersionValue(
String versionUnsavedValue,
Getter versionGetter,
VersionType versionType,
Constructor constructor) {
if ( versionUnsavedValue == null ) {
if ( constructor!=null ) {
final Object defaultValue = versionGetter.get( instantiate( constructor ) );
// if the version of a newly instantiated object is not the same
// as the version seed value, use that as the unsaved-value
return versionType.isEqual( versionType.seed( null ), defaultValue )
? VersionValue.UNDEFINED
: new VersionValue( defaultValue );
}
else {
return VersionValue.UNDEFINED;
}
}
else if ( "undefined".equals( versionUnsavedValue ) ) {
return VersionValue.UNDEFINED;
}
else if ( "null".equals( versionUnsavedValue ) ) {
return VersionValue.NULL;
}
else if ( "negative".equals( versionUnsavedValue ) ) {
return VersionValue.NEGATIVE;
}
else {
// this should not happen since the DTD prevents it
throw new MappingException( "Could not parse version unsaved-value: " + versionUnsavedValue );
}
}
@Override
public Comparator getOwnerVersionComparator() {
if ( !isVersioned() ) {
return null;
}
return ( (VersionType) collectionDescriptor.getOwner().getVersion().getType() ).getComparator();
}
@SuppressWarnings("UnusedReturnValue")
public Builder addEntityConfig(PersistentClass bootEntityDescriptor, AccessType accessType) {
if ( entityConfigsByRootName == null ) {
entityConfigsByRootName = new HashMap<>();
}
// todo (5.3) : this is another place where having `BootstrapContext` / `TypeConfiguration` helps
// would allow us to delay the attempt to resolve the comparator (usual timing issues wrt Type resolution)
final NavigableRole rootEntityName = new NavigableRole( bootEntityDescriptor.getRootClass().getEntityName() );
final EntityDataCachingConfigImpl entityDataCachingConfig = entityConfigsByRootName.computeIfAbsent(
rootEntityName,
x -> new EntityDataCachingConfigImpl(
rootEntityName,
bootEntityDescriptor.isVersioned()
? (Supplier<Comparator>) () -> ( (VersionType) bootEntityDescriptor.getVersion().getType() ).getComparator()
: null,
bootEntityDescriptor.isMutable(),
accessType
)
);
if ( bootEntityDescriptor == bootEntityDescriptor.getRootClass() ) {
entityDataCachingConfig.addCachedType( rootEntityName );
}
else {
entityDataCachingConfig.addCachedType( new NavigableRole( bootEntityDescriptor.getEntityName() ) );
}
return this;
}
/**
* Check the version of the object in the <tt>ResultSet</tt> against
* the object version in the session cache, throwing an exception
* if the version numbers are different
*/
private void checkVersion(
final int i,
final Loadable persister,
final Serializable id,
final Object entity,
final ResultSet rs,
final SessionImplementor session)
throws HibernateException, SQLException {
Object version = session.getPersistenceContext().getEntry( entity ).getVersion();
if ( version != null ) { //null version means the object is in the process of being loaded somewhere else in the ResultSet
VersionType versionType = persister.getVersionType();
Object currentVersion = versionType.nullSafeGet(
rs,
getEntityAliases()[i].getSuffixedVersionAliases(),
session,
null
);
if ( !versionType.isEqual(version, currentVersion) ) {
if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
session.getFactory().getStatisticsImplementor()
.optimisticFailure( persister.getEntityName() );
}
throw new StaleObjectStateException( persister.getEntityName(), id );
}
}
}
/**
* Generates a VersionProperty representation for an entity mapping given its
* version mapping Property.
*
* @param property The version mapping Property.
* @param lazyAvailable Is property lazy loading currently available.
* @return The appropriate VersionProperty definition.
*/
public static VersionProperty buildVersionProperty(Property property, boolean lazyAvailable) {
String mappedUnsavedValue = ( (KeyValue) property.getValue() ).getNullValue();
VersionValue unsavedValue = UnsavedValueFactory.getUnsavedVersionValue(
mappedUnsavedValue,
getGetter( property ),
(VersionType) property.getType(),
getConstructor( property.getPersistentClass() )
);
boolean lazy = lazyAvailable && property.isLazy();
return new VersionProperty(
property.getName(),
property.getNodeName(),
property.getValue().getType(),
lazy,
property.isInsertable(),
property.isUpdateable(),
property.getGeneration() == PropertyGeneration.INSERT || property.getGeneration() == PropertyGeneration.ALWAYS,
property.getGeneration() == PropertyGeneration.ALWAYS,
property.isOptional(),
property.isUpdateable() && !lazy,
property.isOptimisticLocked(),
property.getCascadeStyle(),
unsavedValue
);
}
/**
* Generate the next increment in the optimisitc locking value according
* the {@link VersionType} contract for the version property.
*
* @param version The current version
* @param versionType The version type
* @param session The originating session
* @return The incremented optimistic locking value.
*/
public static Object increment(Object version, VersionType versionType, SessionImplementor session) {
Object next = versionType.next( version, session );
if ( log.isTraceEnabled() ) {
log.trace(
"Incrementing: " +
versionType.toLoggableString( version, session.getFactory() ) +
" to " +
versionType.toLoggableString( next, session.getFactory() )
);
}
return next;
}
public static VersionValue getUnsavedVersionValue(
String versionUnsavedValue,
Getter versionGetter,
VersionType versionType,
Constructor constructor) {
if ( versionUnsavedValue == null ) {
if ( constructor!=null ) {
Object defaultValue = versionGetter.get( instantiate(constructor) );
// if the version of a newly instantiated object is not the same
// as the version seed value, use that as the unsaved-value
return versionType.isEqual( versionType.seed( null ), defaultValue ) ?
VersionValue.UNDEFINED :
new VersionValue( defaultValue );
}
else {
return VersionValue.UNDEFINED;
}
}
else if ( "undefined".equals( versionUnsavedValue ) ) {
return VersionValue.UNDEFINED;
}
else if ( "null".equals( versionUnsavedValue ) ) {
return VersionValue.NULL;
}
else if ( "negative".equals( versionUnsavedValue ) ) {
return VersionValue.NEGATIVE;
}
else {
// this should not happen since the DTD prevents it
throw new MappingException( "Could not parse version unsaved-value: " + versionUnsavedValue );
}
}
public VersionType getVersionType() {
return (VersionType) locateVersionType();
}
@Override
protected void prepareVersioned(AST updateNode, AST versioned) throws SemanticException {
UpdateStatement updateStatement = (UpdateStatement) updateNode;
FromClause fromClause = updateStatement.getFromClause();
if ( versioned != null ) {
// Make sure that the persister is versioned
Queryable persister = fromClause.getFromElement().getQueryable();
if ( !persister.isVersioned() ) {
throw new SemanticException( "increment option specified for update of non-versioned entity" );
}
VersionType versionType = persister.getVersionType();
if ( versionType instanceof UserVersionType ) {
throw new SemanticException( "user-defined version types not supported for increment option" );
}
AST eq = getASTFactory().create( HqlSqlTokenTypes.EQ, "=" );
AST versionPropertyNode = generateVersionPropertyNode( persister );
eq.setFirstChild( versionPropertyNode );
AST versionIncrementNode = null;
if ( isTimestampBasedVersion( versionType ) ) {
versionIncrementNode = getASTFactory().create( HqlSqlTokenTypes.PARAM, "?" );
ParameterSpecification paramSpec = new VersionTypeSeedParameterSpecification( versionType );
( (ParameterNode) versionIncrementNode ).setHqlParameterSpecification( paramSpec );
parameterSpecs.add( 0, paramSpec );
}
else {
// Not possible to simply re-use the versionPropertyNode here as it causes
// OOM errors due to circularity :(
versionIncrementNode = getASTFactory().create( HqlSqlTokenTypes.PLUS, "+" );
versionIncrementNode.setFirstChild( generateVersionPropertyNode( persister ) );
versionIncrementNode.addChild( getASTFactory().create( HqlSqlTokenTypes.IDENT, "1" ) );
}
eq.addChild( versionIncrementNode );
evaluateAssignment( eq, persister, 0 );
AST setClause = updateStatement.getSetClause();
AST currentFirstSetElement = setClause.getFirstChild();
setClause.setFirstChild( eq );
eq.setNextSibling( currentFirstSetElement );
}
}
private boolean isTimestampBasedVersion(VersionType versionType) {
final Class javaType = versionType.getReturnedClass();
return Date.class.isAssignableFrom( javaType )
|| Calendar.class.isAssignableFrom( javaType );
}
public VersionType getVersionType() {
return ( VersionType ) locateVersionType();
}
public VersionTypeSeedParameterSpecification(VersionType type) {
this.type = type;
}
public boolean shouldOverwriteCurrentVersion(Object entity, Object currentVersion, Object newVersion, VersionType versionType) {
throw new AssertionFailure("should not be called");
}
public boolean shouldOverwriteCurrentVersion(Object entity, Object currentVersion, Object newVersion, VersionType versionType) {
return false;
}
public boolean shouldOverwriteCurrentVersion(Object entity, Object currentVersion, Object newVersion, VersionType versionType) {
return true;
}
public boolean shouldOverwriteCurrentVersion(Object entity, Object currentVersion, Object newVersion, VersionType versionType) {
if (versionType==null) return true; //always overwrite nonversioned data
return versionType.getComparator().compare(currentVersion, newVersion) <= 0;
}
protected void prepareVersioned(AST updateNode, AST versioned) throws SemanticException {
UpdateStatement updateStatement = ( UpdateStatement ) updateNode;
FromClause fromClause = updateStatement.getFromClause();
if ( versioned != null ) {
// Make sure that the persister is versioned
Queryable persister = fromClause.getFromElement().getQueryable();
if ( !persister.isVersioned() ) {
throw new SemanticException( "increment option specified for update of non-versioned entity" );
}
VersionType versionType = persister.getVersionType();
if ( versionType instanceof UserVersionType ) {
throw new SemanticException( "user-defined version types not supported for increment option" );
}
AST eq = getASTFactory().create( HqlSqlTokenTypes.EQ, "=" );
AST versionPropertyNode = generateVersionPropertyNode( persister );
eq.setFirstChild( versionPropertyNode );
AST versionIncrementNode = null;
if ( Date.class.isAssignableFrom( versionType.getReturnedClass() ) ) {
versionIncrementNode = getASTFactory().create( HqlSqlTokenTypes.PARAM, "?" );
ParameterSpecification paramSpec = new VersionTypeSeedParameterSpecification( versionType );
( ( ParameterNode ) versionIncrementNode ).setHqlParameterSpecification( paramSpec );
parameters.add( 0, paramSpec );
}
else {
// Not possible to simply re-use the versionPropertyNode here as it causes
// OOM errors due to circularity :(
versionIncrementNode = getASTFactory().create( HqlSqlTokenTypes.PLUS, "+" );
versionIncrementNode.setFirstChild( generateVersionPropertyNode( persister ) );
versionIncrementNode.addChild( getASTFactory().create( HqlSqlTokenTypes.IDENT, "1" ) );
}
eq.addChild( versionIncrementNode );
evaluateAssignment( eq, persister, 0 );
AST setClause = updateStatement.getSetClause();
AST currentFirstSetElement = setClause.getFirstChild();
setClause.setFirstChild( eq );
eq.setNextSibling( currentFirstSetElement );
}
}
/**
* @see EntityPersister#getVersionType()
*/
public VersionType getVersionType() {
return null;
}
/**
* If {@link #isVersioned()}, then what is the type of the property
* holding the locking value.
*
* @return The type of the version property; or null, if not versioned.
*/
VersionType getVersionType();
/**
* Constructs a version seed parameter bind specification.
*
* @param type The version type.
*/
public VersionTypeSeedParameterSpecification(VersionType type) {
this.type = type;
}
/**
* If {@link #isVersioned()}, then what is the type of the property
* holding the locking value.
*
* @return The type of the version property; or null, if not versioned.
*/
public VersionType getVersionType();
public abstract boolean shouldOverwriteCurrentVersion(Object entity, Object currentVersion, Object newVersion, VersionType versionType);