下面列出了怎么用org.hibernate.event.spi.FlushEntityEvent的API类实例代码及写法,或者点击链接到github查看源代码。
private boolean isUpdateNecessary(final FlushEntityEvent event, final boolean mightBeDirty) {
final Status status = event.getEntityEntry().getStatus();
if ( mightBeDirty || status == Status.DELETED ) {
// compare to cached state (ignoring collections unless versioned)
dirtyCheck( event );
if ( isUpdateNecessary( event ) ) {
return true;
}
else {
if ( event.getEntity() instanceof SelfDirtinessTracker ) {
( (SelfDirtinessTracker) event.getEntity() ).$$_hibernate_clearDirtyAttributes();
}
event.getSession()
.getFactory()
.getCustomEntityDirtinessStrategy()
.resetDirty( event.getEntity(), event.getEntityEntry().getPersister(), event.getSession() );
return false;
}
}
else {
return hasDirtyCollections( event, event.getEntityEntry().getPersister(), status );
}
}
protected boolean handleInterception(FlushEntityEvent event) {
SessionImplementor session = event.getSession();
EntityEntry entry = event.getEntityEntry();
EntityPersister persister = entry.getPersister();
Object entity = event.getEntity();
//give the Interceptor a chance to modify property values
final Object[] values = event.getPropertyValues();
final boolean intercepted = invokeInterceptor( session, entity, entry, values, persister );
//now we might need to recalculate the dirtyProperties array
if ( intercepted && event.isDirtyCheckPossible() ) {
dirtyCheck( event );
}
return intercepted;
}
/**
* Performs all necessary checking to determine if an entity needs an SQL update
* to synchronize its state to the database. Modifies the event by side-effect!
* Note: this method is quite slow, avoid calling if possible!
*/
protected final boolean isUpdateNecessary(FlushEntityEvent event) throws HibernateException {
EntityPersister persister = event.getEntityEntry().getPersister();
Status status = event.getEntityEntry().getStatus();
if ( !event.isDirtyCheckPossible() ) {
return true;
}
else {
int[] dirtyProperties = event.getDirtyProperties();
if ( dirtyProperties != null && dirtyProperties.length != 0 ) {
return true; //TODO: suck into event class
}
else {
return hasDirtyCollections( event, persister, status );
}
}
}
private boolean isUpdateNecessary(final FlushEntityEvent event, final boolean mightBeDirty) {
final Status status = event.getEntityEntry().getStatus();
if ( mightBeDirty || status == Status.DELETED ) {
// compare to cached state (ignoring collections unless versioned)
dirtyCheck( event );
if ( isUpdateNecessary( event ) ) {
return true;
}
else {
if ( SelfDirtinessTracker.class.isInstance( event.getEntity() ) ) {
( (SelfDirtinessTracker) event.getEntity() ).$$_hibernate_clearDirtyAttributes();
}
event.getSession()
.getFactory()
.getCustomEntityDirtinessStrategy()
.resetDirty( event.getEntity(), event.getEntityEntry().getPersister(), event.getSession() );
return false;
}
}
else {
return hasDirtyCollections( event, event.getEntityEntry().getPersister(), status );
}
}
protected boolean handleInterception(FlushEntityEvent event) {
SessionImplementor session = event.getSession();
EntityEntry entry = event.getEntityEntry();
EntityPersister persister = entry.getPersister();
Object entity = event.getEntity();
//give the Interceptor a chance to modify property values
final Object[] values = event.getPropertyValues();
final boolean intercepted = invokeInterceptor( session, entity, entry, values, persister );
//now we might need to recalculate the dirtyProperties array
if ( intercepted && event.isDirtyCheckPossible() ) {
dirtyCheck( event );
}
return intercepted;
}
/**
* Performs all necessary checking to determine if an entity needs an SQL update
* to synchronize its state to the database. Modifies the event by side-effect!
* Note: this method is quite slow, avoid calling if possible!
*/
protected final boolean isUpdateNecessary(FlushEntityEvent event) throws HibernateException {
EntityPersister persister = event.getEntityEntry().getPersister();
Status status = event.getEntityEntry().getStatus();
if ( !event.isDirtyCheckPossible() ) {
return true;
}
else {
int[] dirtyProperties = event.getDirtyProperties();
if ( dirtyProperties != null && dirtyProperties.length != 0 ) {
return true; //TODO: suck into event class
}
else {
return hasDirtyCollections( event, persister, status );
}
}
}
private boolean updated(FlushEntityEvent event) {
final EntityEntry entry = event.getEntityEntry();
final Object entity = event.getEntity();
int[] dirtyProperties;
EntityPersister persister = entry.getPersister();
final Object[] values = event.getPropertyValues();
SessionImplementor session = event.getSession();
if ( event.hasDatabaseSnapshot() ) {
dirtyProperties = persister.findModified( event.getDatabaseSnapshot(), values, entity, session );
}
else {
dirtyProperties = persister.findDirty( values, entry.getLoadedState(), entity, session );
}
return dirtyProperties != null;
}
/**
* Flushes a single entity's state to the database, by scheduling
* an update action, if necessary
*/
public void onFlushEntity(FlushEntityEvent event) throws HibernateException {
final Object entity = event.getEntity();
final EntityEntry entry = event.getEntityEntry();
final EventSource session = event.getSession();
final EntityPersister persister = entry.getPersister();
final Status status = entry.getStatus();
final Type[] types = persister.getPropertyTypes();
final boolean mightBeDirty = entry.requiresDirtyCheck( entity );
final Object[] values = getValues( entity, entry, mightBeDirty, session );
event.setPropertyValues( values );
//TODO: avoid this for non-new instances where mightBeDirty==false
boolean substitute = wrapCollections( session, persister, types, values );
if ( isUpdateNecessary( event, mightBeDirty ) ) {
substitute = scheduleUpdate( event ) || substitute;
}
if ( status != Status.DELETED ) {
// now update the object .. has to be outside the main if block above (because of collections)
if ( substitute ) {
persister.setPropertyValues( entity, values );
}
// Search for collections by reachability, updating their role.
// We don't want to touch collections reachable from a deleted object
if ( persister.hasCollections() ) {
new FlushVisitor( session, entity ).processEntityPropertyValues( values, types );
}
}
}
/**
* Convenience method to retrieve an entities next version value
*/
private Object getNextVersion(FlushEntityEvent event) throws HibernateException {
EntityEntry entry = event.getEntityEntry();
EntityPersister persister = entry.getPersister();
if ( persister.isVersioned() ) {
Object[] values = event.getPropertyValues();
if ( entry.isBeingReplicated() ) {
return Versioning.getVersion( values, persister );
}
else {
int[] dirtyProperties = event.getDirtyProperties();
final boolean isVersionIncrementRequired = isVersionIncrementRequired(
event,
entry,
persister,
dirtyProperties
);
final Object nextVersion = isVersionIncrementRequired ?
Versioning.increment( entry.getVersion(), persister.getVersionType(), event.getSession() ) :
entry.getVersion(); //use the current version
Versioning.setVersion( values, nextVersion, persister );
return nextVersion;
}
}
else {
return null;
}
}
private boolean isVersionIncrementRequired(
FlushEntityEvent event,
EntityEntry entry,
EntityPersister persister,
int[] dirtyProperties) {
return entry.getStatus() != Status.DELETED && (
dirtyProperties == null ||
Versioning.isVersionIncrementRequired(
dirtyProperties,
event.hasDirtyCollection(),
persister.getPropertyVersionability()
)
);
}
/**
* 1. detect any dirty entities
* 2. schedule any entity updates
* 3. search out any reachable collections
*/
private int flushEntities(final FlushEvent event, final PersistenceContext persistenceContext) throws HibernateException {
LOG.trace( "Flushing entities and processing referenced collections" );
final EventSource source = event.getSession();
final Iterable<FlushEntityEventListener> flushListeners =
source.getFactory().getServiceRegistry()
.getService( EventListenerRegistry.class )
.getEventListenerGroup( EventType.FLUSH_ENTITY )
.listeners();
// Among other things, updateReachables() will recursively load all
// collections that are moving roles. This might cause entities to
// be loaded.
// So this needs to be safe from concurrent modification problems.
final Map.Entry<Object,EntityEntry>[] entityEntries = persistenceContext.reentrantSafeEntityEntries();
final int count = entityEntries.length;
for ( Map.Entry<Object,EntityEntry> me : entityEntries ) {
// Update the status of the object and if necessary, schedule an update
EntityEntry entry = me.getValue();
Status status = entry.getStatus();
if ( status != Status.LOADING && status != Status.GONE ) {
final FlushEntityEvent entityEvent = new FlushEntityEvent( source, me.getKey(), entry );
for ( FlushEntityEventListener listener : flushListeners ) {
listener.onFlushEntity( entityEvent );
}
}
}
source.getActionQueue().sortActions();
return count;
}
/**
* Flushes a single entity's state to the database, by scheduling
* an update action, if necessary
*/
public void onFlushEntity(FlushEntityEvent event) throws HibernateException {
final Object entity = event.getEntity();
final EntityEntry entry = event.getEntityEntry();
final EventSource session = event.getSession();
final EntityPersister persister = entry.getPersister();
final Status status = entry.getStatus();
final Type[] types = persister.getPropertyTypes();
final boolean mightBeDirty = entry.requiresDirtyCheck( entity );
final Object[] values = getValues( entity, entry, mightBeDirty, session );
event.setPropertyValues( values );
//TODO: avoid this for non-new instances where mightBeDirty==false
boolean substitute = wrapCollections( session, persister, types, values );
if ( isUpdateNecessary( event, mightBeDirty ) ) {
substitute = scheduleUpdate( event ) || substitute;
}
if ( status != Status.DELETED ) {
// now update the object .. has to be outside the main if block above (because of collections)
if ( substitute ) {
persister.setPropertyValues( entity, values );
}
// Search for collections by reachability, updating their role.
// We don't want to touch collections reachable from a deleted object
if ( persister.hasCollections() ) {
new FlushVisitor( session, entity ).processEntityPropertyValues( values, types );
}
}
}
/**
* Convenience method to retrieve an entities next version value
*/
private Object getNextVersion(FlushEntityEvent event) throws HibernateException {
EntityEntry entry = event.getEntityEntry();
EntityPersister persister = entry.getPersister();
if ( persister.isVersioned() ) {
Object[] values = event.getPropertyValues();
if ( entry.isBeingReplicated() ) {
return Versioning.getVersion( values, persister );
}
else {
int[] dirtyProperties = event.getDirtyProperties();
final boolean isVersionIncrementRequired = isVersionIncrementRequired(
event,
entry,
persister,
dirtyProperties
);
final Object nextVersion = isVersionIncrementRequired ?
Versioning.increment( entry.getVersion(), persister.getVersionType(), event.getSession() ) :
entry.getVersion(); //use the current version
Versioning.setVersion( values, nextVersion, persister );
return nextVersion;
}
}
else {
return null;
}
}
/**
* 1. detect any dirty entities
* 2. schedule any entity updates
* 3. search out any reachable collections
*/
private int flushEntities(final FlushEvent event, final PersistenceContext persistenceContext) throws HibernateException {
LOG.trace( "Flushing entities and processing referenced collections" );
final EventSource source = event.getSession();
final Iterable<FlushEntityEventListener> flushListeners = source.getFactory().getServiceRegistry()
.getService( EventListenerRegistry.class )
.getEventListenerGroup( EventType.FLUSH_ENTITY )
.listeners();
// Among other things, updateReachables() will recursively load all
// collections that are moving roles. This might cause entities to
// be loaded.
// So this needs to be safe from concurrent modification problems.
final Map.Entry<Object,EntityEntry>[] entityEntries = persistenceContext.reentrantSafeEntityEntries();
final int count = entityEntries.length;
for ( Map.Entry<Object,EntityEntry> me : entityEntries ) {
// Update the status of the object and if necessary, schedule an update
EntityEntry entry = me.getValue();
Status status = entry.getStatus();
if ( status != Status.LOADING && status != Status.GONE ) {
final FlushEntityEvent entityEvent = new FlushEntityEvent( source, me.getKey(), entry );
for ( FlushEntityEventListener listener : flushListeners ) {
listener.onFlushEntity( entityEvent );
}
}
}
source.getActionQueue().sortActions();
return count;
}
private boolean scheduleUpdate(final FlushEntityEvent event) {
final EntityEntry entry = event.getEntityEntry();
final EventSource session = event.getSession();
final Object entity = event.getEntity();
final Status status = entry.getStatus();
final EntityPersister persister = entry.getPersister();
final Object[] values = event.getPropertyValues();
if ( LOG.isTraceEnabled() ) {
if ( status == Status.DELETED ) {
if ( !persister.isMutable() ) {
LOG.tracev(
"Updating immutable, deleted entity: {0}",
MessageHelper.infoString( persister, entry.getId(), session.getFactory() )
);
}
else if ( !entry.isModifiableEntity() ) {
LOG.tracev(
"Updating non-modifiable, deleted entity: {0}",
MessageHelper.infoString( persister, entry.getId(), session.getFactory() )
);
}
else {
LOG.tracev(
"Updating deleted entity: ",
MessageHelper.infoString( persister, entry.getId(), session.getFactory() )
);
}
}
else {
LOG.tracev(
"Updating entity: {0}",
MessageHelper.infoString( persister, entry.getId(), session.getFactory() )
);
}
}
final boolean intercepted = !entry.isBeingReplicated() && handleInterception( event );
// increment the version number (if necessary)
final Object nextVersion = getNextVersion( event );
// if it was dirtied by a collection only
int[] dirtyProperties = event.getDirtyProperties();
if ( event.isDirtyCheckPossible() && dirtyProperties == null ) {
if ( !intercepted && !event.hasDirtyCollection() ) {
throw new AssertionFailure( "dirty, but no dirty properties" );
}
dirtyProperties = ArrayHelper.EMPTY_INT_ARRAY;
}
// check nullability but do not doAfterTransactionCompletion command execute
// we'll use scheduled updates for that.
new Nullability( session ).checkNullability( values, persister, true );
// schedule the update
// note that we intentionally do _not_ pass in currentPersistentState!
session.unwrap(ReactiveSession.class).getReactiveActionQueue().addAction(
new ReactiveEntityUpdateAction(
entry.getId(),
values,
dirtyProperties,
event.hasDirtyCollection(),
( status == Status.DELETED && !entry.isModifiableEntity() ?
persister.getPropertyValues( entity ) :
entry.getLoadedState() ),
entry.getVersion(),
nextVersion,
entity,
entry.getRowId(),
persister,
session
)
);
return intercepted;
}
private DirtyCheckAttributeInfoImpl(FlushEntityEvent event) {
this.event = event;
this.persister = event.getEntityEntry().getPersister();
this.numberOfAttributes = persister.getPropertyNames().length;
}
private boolean scheduleUpdate(final FlushEntityEvent event) {
final EntityEntry entry = event.getEntityEntry();
final EventSource session = event.getSession();
final Object entity = event.getEntity();
final Status status = entry.getStatus();
final EntityPersister persister = entry.getPersister();
final Object[] values = event.getPropertyValues();
if ( LOG.isTraceEnabled() ) {
if ( status == Status.DELETED ) {
if ( !persister.isMutable() ) {
LOG.tracev(
"Updating immutable, deleted entity: {0}",
MessageHelper.infoString( persister, entry.getId(), session.getFactory() )
);
}
else if ( !entry.isModifiableEntity() ) {
LOG.tracev(
"Updating non-modifiable, deleted entity: {0}",
MessageHelper.infoString( persister, entry.getId(), session.getFactory() )
);
}
else {
LOG.tracev(
"Updating deleted entity: ",
MessageHelper.infoString( persister, entry.getId(), session.getFactory() )
);
}
}
else {
LOG.tracev(
"Updating entity: {0}",
MessageHelper.infoString( persister, entry.getId(), session.getFactory() )
);
}
}
final boolean intercepted = !entry.isBeingReplicated() && handleInterception( event );
// increment the version number (if necessary)
final Object nextVersion = getNextVersion( event );
// if it was dirtied by a collection only
int[] dirtyProperties = event.getDirtyProperties();
if ( event.isDirtyCheckPossible() && dirtyProperties == null ) {
if ( !intercepted && !event.hasDirtyCollection() ) {
throw new AssertionFailure( "dirty, but no dirty properties" );
}
dirtyProperties = ArrayHelper.EMPTY_INT_ARRAY;
}
// check nullability but do not doAfterTransactionCompletion command execute
// we'll use scheduled updates for that.
new Nullability( session ).checkNullability( values, persister, true );
// schedule the update
// note that we intentionally do _not_ pass in currentPersistentState!
session.getActionQueue().addAction(
new EntityUpdateAction(
entry.getId(),
values,
dirtyProperties,
event.hasDirtyCollection(),
( status == Status.DELETED && !entry.isModifiableEntity() ?
persister.getPropertyValues( entity ) :
entry.getLoadedState() ),
entry.getVersion(),
nextVersion,
entity,
entry.getRowId(),
persister,
session
)
);
return intercepted;
}
private DirtyCheckAttributeInfoImpl(FlushEntityEvent event) {
this.event = event;
this.persister = event.getEntityEntry().getPersister();
this.numberOfAttributes = persister.getPropertyNames().length;
}
@Override
public void onFlushEntity(FlushEntityEvent event) throws HibernateException {
String[] properties = event.getEntityEntry().getPersister().getPropertyNames();
Object[] loadedState = event.getEntityEntry().getLoadedState();
}
private void incrementRootVersion(FlushEntityEvent event, Object root) {
EntityEntry entityEntry = event.getSession().getPersistenceContext().getEntry( Hibernate.unproxy( root) );
if(entityEntry.getStatus() != Status.DELETED) {
event.getSession().lock(root, LockMode.OPTIMISTIC_FORCE_INCREMENT);
}
}
private boolean deleted(FlushEntityEvent event) {
return event.getEntityEntry().getStatus() == Status.DELETED;
}