下面列出了怎么用org.hibernate.engine.spi.Status的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* process cascade save/update at the start of a flush to discover
* any newly referenced entity that must be passed to saveOrUpdate(),
* and also apply orphan delete
*/
private CompletionStage<Void> prepareEntityFlushes(EventSource session, PersistenceContext persistenceContext) throws HibernateException {
LOG.debug( "Processing flush-time cascades" );
CompletionStage<Void> stage = CompletionStages.nullFuture();
final IdentitySet copiedAlready = new IdentitySet( 10 );
//safe from concurrent modification because of how concurrentEntries() is implemented on IdentityMap
for ( Map.Entry<Object, EntityEntry> me : persistenceContext.reentrantSafeEntityEntries() ) {
EntityEntry entry = me.getValue();
Status status = entry.getStatus();
if ( status == Status.MANAGED || status == Status.SAVING || status == Status.READ_ONLY ) {
stage = stage.thenCompose( v -> cascadeOnFlush( session, entry.getPersister(), me.getKey(), copiedAlready ) );
}
}
return stage;
}
/**
* @deprecated the tenantId and entityMode parameters where removed: this constructor accepts but ignores them.
* Use the other constructor!
*/
@Deprecated
public MutableEntityEntry(
final Status status,
final Object[] loadedState,
final Object rowId,
final Serializable id,
final Object version,
final LockMode lockMode,
final boolean existsInDatabase,
final EntityPersister persister,
final EntityMode entityMode,
final String tenantId,
final boolean disableVersionIncrement,
final PersistenceContext persistenceContext) {
this( status, loadedState, rowId, id, version, lockMode, existsInDatabase,
persister,disableVersionIncrement, persistenceContext
);
}
/**
* This for is used during custom deserialization handling
*/
@SuppressWarnings( {"JavaDoc"})
private MutableEntityEntry(
final SessionFactoryImplementor factory,
final String entityName,
final Serializable id,
final Status status,
final Status previousStatus,
final Object[] loadedState,
final Object[] deletedState,
final Object version,
final LockMode lockMode,
final boolean existsInDatabase,
final boolean isBeingReplicated,
final PersistenceContext persistenceContext) {
super( factory, entityName, id, status, previousStatus, loadedState, deletedState,
version, lockMode, existsInDatabase, isBeingReplicated, persistenceContext
);
}
/**
* Custom deserialization routine used during deserialization of a
* Session/PersistenceContext for increased performance.
*
* @param ois The stream from which to read the entry.
* @param persistenceContext The context being deserialized.
*
* @return The deserialized EntityEntry
*
* @throws java.io.IOException If a stream error occurs
* @throws ClassNotFoundException If any of the classes declared in the stream
* cannot be found
*/
public static EntityEntry deserialize(
ObjectInputStream ois,
PersistenceContext persistenceContext) throws IOException, ClassNotFoundException {
String previousStatusString;
return new MutableEntityEntry(
persistenceContext.getSession().getFactory(),
(String) ois.readObject(),
(Serializable) ois.readObject(),
Status.valueOf( (String) ois.readObject() ),
( previousStatusString = (String) ois.readObject() ).length() == 0
? null
: Status.valueOf( previousStatusString ),
(Object[]) ois.readObject(),
(Object[]) ois.readObject(),
ois.readObject(),
LockMode.valueOf( (String) ois.readObject() ),
ois.readBoolean(),
ois.readBoolean(),
persistenceContext
);
}
/**
* @deprecated the tenantId and entityMode parameters where removed: this constructor accepts but ignores them.
* Use the other constructor!
*/
@Deprecated
public AbstractEntityEntry(
final Status status,
final Object[] loadedState,
final Object rowId,
final Serializable id,
final Object version,
final LockMode lockMode,
final boolean existsInDatabase,
final EntityPersister persister,
final EntityMode entityMode,
final String tenantId,
final boolean disableVersionIncrement,
final PersistenceContext persistenceContext) {
this( status, loadedState, rowId, id, version, lockMode, existsInDatabase,
persister,disableVersionIncrement, persistenceContext
);
}
@Override
public void setReadOnly(boolean readOnly, Object entity) {
if ( readOnly == isReadOnly() ) {
// simply return since the status is not being changed
return;
}
if ( readOnly ) {
setStatus( Status.READ_ONLY );
loadedState = null;
}
else {
if ( ! persister.isMutable() ) {
throw new IllegalStateException( "Cannot make an immutable entity modifiable." );
}
setStatus( Status.MANAGED );
loadedState = getPersister().getPropertyValues( entity );
getPersistenceContext().getNaturalIdHelper().manageLocalNaturalIdCrossReference(
persister,
id,
loadedState,
null,
CachedNaturalIdValueSource.LOAD
);
}
}
@Override
public EntityEntry addEntity(
final Object entity,
final Status status,
final Object[] loadedState,
final EntityKey entityKey,
final Object version,
final LockMode lockMode,
final boolean existsInDatabase,
final EntityPersister persister,
final boolean disableVersionIncrement) {
addEntity( entityKey, entity );
return addEntry(
entity,
status,
loadedState,
null,
entityKey.getIdentifier(),
version,
lockMode,
existsInDatabase,
persister,
disableVersionIncrement
);
}
public ImmutableEntityEntry(
final Status status,
final Object[] loadedState,
final Object rowId,
final Serializable id,
final Object version,
final LockMode lockMode,
final boolean existsInDatabase,
final EntityPersister persister,
final boolean disableVersionIncrement,
final PersistenceContext persistenceContext) {
super(
status,
loadedState,
rowId,
id,
version,
lockMode,
existsInDatabase,
persister,
disableVersionIncrement,
// purposefully do not pass along the session/persistence-context : HHH-10251
null
);
}
/**
* This for is used during custom deserialization handling
*/
@SuppressWarnings( {"JavaDoc"})
private ImmutableEntityEntry(
final SessionFactoryImplementor factory,
final String entityName,
final Serializable id,
final Status status,
final Status previousStatus,
final Object[] loadedState,
final Object[] deletedState,
final Object version,
final LockMode lockMode,
final boolean existsInDatabase,
final boolean isBeingReplicated,
final PersistenceContext persistenceContext) {
super( factory, entityName, id, status, previousStatus, loadedState, deletedState,
version, lockMode, existsInDatabase, isBeingReplicated, persistenceContext
);
}
/**
* Custom deserialization routine used during deserialization of a
* Session/PersistenceContext for increased performance.
*
* @param ois The stream from which to read the entry.
* @param persistenceContext The context being deserialized.
*
* @return The deserialized EntityEntry
*
* @throws java.io.IOException If a stream error occurs
* @throws ClassNotFoundException If any of the classes declared in the stream
* cannot be found
*/
public static EntityEntry deserialize(
ObjectInputStream ois,
PersistenceContext persistenceContext) throws IOException, ClassNotFoundException {
String previousStatusString;
return new ImmutableEntityEntry(
persistenceContext.getSession().getFactory(),
(String) ois.readObject(),
(Serializable) ois.readObject(),
Status.valueOf( (String) ois.readObject() ),
( previousStatusString = (String) ois.readObject() ).length() == 0
? null
: Status.valueOf( previousStatusString ),
(Object[]) ois.readObject(),
(Object[]) ois.readObject(),
ois.readObject(),
LockMode.valueOf( (String) ois.readObject() ),
ois.readBoolean(),
ois.readBoolean(),
null
);
}
/**
* Add an uninitialized instance of an entity class, as a placeholder to ensure object
* identity. Must be called before <tt>postHydrate()</tt>.
*
* Create a "temporary" entry for a newly instantiated entity. The entity is uninitialized,
* but we need the mapping from id to instance in order to guarantee uniqueness.
*
* @param key The entity key
* @param object The entity instance
* @param persister The entity persister
* @param lockMode The lock mode
* @param session The Session
*/
public static void addUninitializedEntity(
final EntityKey key,
final Object object,
final EntityPersister persister,
final LockMode lockMode,
final SharedSessionContractImplementor session) {
session.getPersistenceContext().addEntity(
object,
Status.LOADING,
null,
key,
null,
lockMode,
true,
persister,
false
);
}
/**
* Same as {@link #addUninitializedEntity}, but here for an entity from the second level cache
*
* @param key The entity key
* @param object The entity instance
* @param persister The entity persister
* @param lockMode The lock mode
* @param version The version
* @param session The Session
*/
public static void addUninitializedCachedEntity(
final EntityKey key,
final Object object,
final EntityPersister persister,
final LockMode lockMode,
final Object version,
final SharedSessionContractImplementor session) {
session.getPersistenceContext().addEntity(
object,
Status.LOADING,
null,
key,
version,
lockMode,
true,
persister,
false
);
}
@Override
public EntityEntry createEntityEntry(
Status status,
Object[] loadedState,
Object rowId,
Serializable id,
Object version,
LockMode lockMode,
boolean existsInDatabase,
EntityPersister persister,
boolean disableVersionIncrement,
PersistenceContext persistenceContext) {
return new MutableEntityEntry(
status,
loadedState,
rowId,
id,
version,
lockMode,
existsInDatabase,
persister,
disableVersionIncrement,
persistenceContext
);
}
@Override
public EntityEntry createEntityEntry(
Status status,
Object[] loadedState,
Object rowId,
Serializable id,
Object version,
LockMode lockMode,
boolean existsInDatabase,
EntityPersister persister,
boolean disableVersionIncrement,
PersistenceContext persistenceContext) {
return new ImmutableEntityEntry(
status,
loadedState,
rowId,
id,
version,
lockMode,
existsInDatabase,
persister,
disableVersionIncrement,
persistenceContext
);
}
@Override
public LockMode getCurrentLockMode(Object object) throws HibernateException {
checkOpen();
checkTransactionSynchStatus();
if ( object == null ) {
throw new NullPointerException( "null object passed to getCurrentLockMode()" );
}
if ( object instanceof HibernateProxy ) {
object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation( this );
if ( object == null ) {
return LockMode.NONE;
}
}
EntityEntry e = persistenceContext.getEntry( object );
if ( e == null ) {
throw new TransientObjectException( "Given object not associated with the session" );
}
if ( e.getStatus() != Status.MANAGED ) {
throw new ObjectDeletedException(
"The given object was deleted",
e.getId(),
e.getPersister().getEntityName()
);
}
return e.getLockMode();
}
protected Serializable performSaveOrUpdate(SaveOrUpdateEvent event) {
// this implementation is supposed to tolerate incorrect unsaved-value
// mappings, for the purpose of backward-compatibility
EntityEntry entry = event.getSession().getPersistenceContext().getEntry( event.getEntity() );
if ( entry!=null ) {
if ( entry.getStatus()== Status.DELETED ) {
throw new ObjectDeletedException( "deleted instance passed to update()", null, event.getEntityName() );
}
else {
return entityIsPersistent(event);
}
}
else {
entityIsDetached(event);
return null;
}
}
private Object[] getValues(Object entity, EntityEntry entry, boolean mightBeDirty, SessionImplementor session) {
final Object[] loadedState = entry.getLoadedState();
final Status status = entry.getStatus();
final EntityPersister persister = entry.getPersister();
final Object[] values;
if ( status == Status.DELETED ) {
//grab its state saved at deletion
values = entry.getDeletedState();
}
else if ( !mightBeDirty && loadedState != null ) {
values = loadedState;
}
else {
checkId( entity, persister, entry.getId(), session );
// grab its current state
values = persister.getPropertyValues( entity );
checkNaturalId( persister, entry, values, loadedState, session );
}
return values;
}
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 invokeInterceptor(
SessionImplementor session,
Object entity,
EntityEntry entry,
final Object[] values,
EntityPersister persister) {
boolean isDirty = false;
if ( entry.getStatus() != Status.DELETED ) {
if ( callbackRegistry.preUpdate( entity ) ) {
isDirty = copyState( entity, persister.getPropertyTypes(), values, session.getFactory() );
}
}
final boolean answerFromInterceptor = session.getInterceptor().onFlushDirty(
entity,
entry.getId(),
values,
entry.getLoadedState(),
persister.getPropertyNames(),
persister.getPropertyTypes()
);
return answerFromInterceptor || isDirty;
}
/**
* 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 );
}
}
}
/**
* The given save-update event named a transient entity.
* <p/>
* Here, we will perform the save processing.
*
* @param event The save event to be handled.
*
* @return The entity's identifier after saving.
*/
protected Serializable entityIsTransient(SaveOrUpdateEvent event) {
LOG.trace( "Saving transient instance" );
final EventSource source = event.getSession();
EntityEntry entityEntry = event.getEntry();
if ( entityEntry != null ) {
if ( entityEntry.getStatus() == Status.DELETED ) {
source.forceFlush( entityEntry );
}
else {
throw new AssertionFailure( "entity was persistent" );
}
}
Serializable id = saveWithGeneratedOrRequestedId( event );
source.getPersistenceContext().reassociateProxy( event.getObject(), id );
return id;
}
private void makeEntityCircularReferenceSafe(ReferenceCacheEntryImpl referenceCacheEntry,
EventSource session,
Object entity,
EntityKey entityKey) {
// make it circular-reference safe
final StatefulPersistenceContext statefulPersistenceContext = (StatefulPersistenceContext) session.getPersistenceContext();
if ( (entity instanceof ManagedEntity) ) {
statefulPersistenceContext.addReferenceEntry(
entity,
Status.READ_ONLY
);
}
else {
TwoPhaseLoad.addUninitializedCachedEntity(
entityKey,
entity,
referenceCacheEntry.getSubclassPersister(),
LockMode.NONE,
referenceCacheEntry.getVersion(),
session
);
}
statefulPersistenceContext.initializeNonLazyCollections();
}
/**
* process cascade save/update at the start of a flush to discover
* any newly referenced entity that must be passed to saveOrUpdate(),
* and also apply orphan delete
*/
private void prepareEntityFlushes(EventSource session, PersistenceContext persistenceContext) throws HibernateException {
LOG.debug( "Processing flush-time cascades" );
final Object anything = getAnything();
//safe from concurrent modification because of how concurrentEntries() is implemented on IdentityMap
for ( Map.Entry<Object,EntityEntry> me : persistenceContext.reentrantSafeEntityEntries() ) {
// for ( Map.Entry me : IdentityMap.concurrentEntries( persistenceContext.getEntityEntries() ) ) {
EntityEntry entry = (EntityEntry) me.getValue();
Status status = entry.getStatus();
if ( status == Status.MANAGED || status == Status.SAVING || status == Status.READ_ONLY ) {
cascadeOnFlush( session, entry.getPersister(), me.getKey(), anything );
}
}
}
/**
* Make the entity "managed" by the persistence context.
*/
public final void makeEntityManaged() {
nullifyTransientReferencesIfNotAlready();
final Object version = Versioning.getVersion( getState(), getPersister() );
getSession().getPersistenceContext().addEntity(
getInstance(),
( getPersister().isMutable() ? Status.MANAGED : Status.READ_ONLY ),
getState(),
getEntityKey(),
version,
LockMode.WRITE,
isExecuted,
getPersister(),
isVersionIncrementDisabled
);
}
/**
* Sets the target object to read-write, allowing Hibernate to dirty check it and auto-flush changes.
*
* @see #setObjectToReadyOnly(Object, org.hibernate.SessionFactory)
*
* @param target The target object
* @param sessionFactory The SessionFactory instance
*/
public static void setObjectToReadWrite(final Object target, SessionFactory sessionFactory) {
Session session = sessionFactory.getCurrentSession();
if (!canModifyReadWriteState(session, target)) {
return;
}
SessionImplementor sessionImpl = (SessionImplementor) session;
EntityEntry ee = sessionImpl.getPersistenceContext().getEntry(target);
if (ee == null || ee.getStatus() != Status.READ_ONLY) {
return;
}
Object actualTarget = target;
if (target instanceof HibernateProxy) {
actualTarget = ((HibernateProxy)target).getHibernateLazyInitializer().getImplementation();
}
session.setReadOnly(actualTarget, false);
session.setHibernateFlushMode(FlushMode.AUTO);
incrementVersion(target);
}
@Test()
public void whenDelete_thenMarkDeleted() throws Exception {
SessionFactory sessionFactory = HibernateLifecycleUtil.getSessionFactory();
try (Session session = sessionFactory.openSession()) {
Transaction transaction = startTransaction(session);
FootballPlayer neymar = new FootballPlayer();
neymar.setName("Neymar");
session.save(neymar);
transaction.commit();
transaction = startTransaction(session);
session.delete(neymar);
assertThat(getManagedEntities(session).get(0).getStatus()).isEqualTo(Status.DELETED);
transaction.commit();
}
}
/**
* Make the entity "managed" by the persistence context.
*
* @see org.hibernate.action.internal.AbstractEntityInsertAction#makeEntityManaged()
*/
default CompletionStage<Void> reactiveMakeEntityManaged() {
return reactiveNullifyTransientReferencesIfNotAlready()
.thenAccept( v -> getSession().getPersistenceContextInternal().addEntity(
getInstance(),
( getPersister().isMutable() ? Status.MANAGED : Status.READ_ONLY ),
getState(),
getEntityKey(),
Versioning.getVersion( getState(), getPersister() ),
LockMode.WRITE,
isExecuted(),
getPersister(),
isVersionIncrementDisabled()
));
}
/**
* If there is already a corresponding proxy associated with the
* persistence context, return it; otherwise create a proxy, associate it
* with the persistence context, and return the just-created proxy.
*
* @param event The initiating load request event
* @param persister The persister corresponding to the entity to be loaded
* @param keyToLoad The key of the entity to be loaded
* @param options The defined load options
* @param persistenceContext The originating session
*
* @return The created/existing proxy
*/
private Object createProxyIfNecessary(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options,
final PersistenceContext persistenceContext) {
Object existing = persistenceContext.getEntity( keyToLoad );
final boolean traceEnabled = LOG.isTraceEnabled();
if ( existing != null ) {
// return existing object or initialized proxy (unless deleted)
if ( traceEnabled ) {
LOG.trace( "Entity found in session cache" );
}
if ( options.isCheckDeleted() ) {
EntityEntry entry = persistenceContext.getEntry( existing );
Status status = entry.getStatus();
if ( status == Status.DELETED || status == Status.GONE ) {
return null;
}
}
return existing;
}
if ( traceEnabled ) {
LOG.trace( "Creating new proxy for entity" );
}
return createProxy( event, persister, keyToLoad, persistenceContext );
}
/**
* 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;
}
public MutableEntityEntry(
final Status status,
final Object[] loadedState,
final Object rowId,
final Serializable id,
final Object version,
final LockMode lockMode,
final boolean existsInDatabase,
final EntityPersister persister,
final boolean disableVersionIncrement,
final PersistenceContext persistenceContext) {
super( status, loadedState, rowId, id, version, lockMode, existsInDatabase, persister,
disableVersionIncrement, persistenceContext
);
}