📄 statefulpersistencecontext.java
字号:
// $Id: StatefulPersistenceContext.java 9194 2006-02-01 19:59:07Z steveebersole $
package org.hibernate.engine;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.ReferenceMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.AssertionFailure;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.NonUniqueObjectException;
import org.hibernate.PersistentObjectException;
import org.hibernate.TransientObjectException;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.tuple.ElementWrapper;
import org.hibernate.util.IdentityMap;
import org.hibernate.util.MarkerObject;
/**
* A <tt>PersistenceContext</tt> represents the state of persistent "stuff" which
* Hibernate is tracking. This includes persistent entities, collections,
* as well as proxies generated.
* </p>
* There is meant to be a one-to-one correspondence between a SessionImpl and
* a PersistentContext. The SessionImpl uses the PersistentContext to track
* the current state of its context. Event-listeners then use the
* PersistentContext to drive their processing.
*
* @author Steve Ebersole
*/
public class StatefulPersistenceContext implements PersistenceContext {
public static final Object NO_ROW = new MarkerObject( "NO_ROW" );
private static final Log log = LogFactory.getLog( StatefulPersistenceContext.class );
private static final Log PROXY_WARN_LOG = LogFactory.getLog( StatefulPersistenceContext.class.getName() + ".ProxyWarnLog" );
private static final int INIT_COLL_SIZE = 8;
private SessionImplementor session;
// Loaded entity instances, by EntityKey
private Map entitiesByKey;
// Loaded entity instances, by EntityUniqueKey
private Map entitiesByUniqueKey;
// Identity map of EntityEntry instances, by the entity instance
private Map entityEntries;
// Entity proxies, by EntityKey
private Map proxiesByKey;
// Snapshots of current database state for entities
// that have *not* been loaded
private Map entitySnapshotsByKey;
// Identity map of array holder ArrayHolder instances, by the array instance
private Map arrayHolders;
// Identity map of CollectionEntry instances, by the collection wrapper
private Map collectionEntries;
// Collection wrappers, by the CollectionKey
private Map collectionsByKey; //key=CollectionKey, value=PersistentCollection
// Set of EntityKeys of deleted objects
private HashSet nullifiableEntityKeys;
// properties that we have tried to load, and not found in the database
private HashSet nullAssociations;
// A list of collection wrappers that were instantiating during result set
// processing, that we will need to initialize at the end of the query
private List nonlazyCollections;
// A container for collections we load up when the owning entity is not
// yet loaded ... for now, this is purely transient!
private Map unownedCollections;
private int cascading = 0;
private int loadCounter = 0;
private boolean flushing = false;
private boolean hasNonReadOnlyEntities = false;
private CollectionLoadContext collectionLoadContext;
private BatchFetchQueue batchFetchQueue;
/**
* Constructs a PersistentContext, bound to the given session.
*
* @param session The session "owning" this context.
*/
public StatefulPersistenceContext(SessionImplementor session) {
this.session = session;
entitiesByKey = new HashMap( INIT_COLL_SIZE );
entitiesByUniqueKey = new HashMap( INIT_COLL_SIZE );
proxiesByKey = new ReferenceMap( ReferenceMap.HARD, ReferenceMap.WEAK );
entitySnapshotsByKey = new HashMap( INIT_COLL_SIZE );
entityEntries = IdentityMap.instantiateSequenced( INIT_COLL_SIZE );
collectionEntries = IdentityMap.instantiateSequenced( INIT_COLL_SIZE );
collectionsByKey = new HashMap( INIT_COLL_SIZE );
arrayHolders = IdentityMap.instantiate( INIT_COLL_SIZE );
nullifiableEntityKeys = new HashSet();
initTransientState();
}
private void initTransientState() {
nullAssociations = new HashSet( INIT_COLL_SIZE );
nonlazyCollections = new ArrayList( INIT_COLL_SIZE );
}
public boolean isStateless() {
return false;
}
public SessionImplementor getSession() {
return session;
}
public CollectionLoadContext getCollectionLoadContext() {
if (collectionLoadContext==null) {
collectionLoadContext = new CollectionLoadContext(this);
}
return collectionLoadContext;
}
public void addUnownedCollection(CollectionKey key, PersistentCollection collection) {
if (unownedCollections==null) {
unownedCollections = new HashMap(8);
}
unownedCollections.put(key, collection);
}
public PersistentCollection useUnownedCollection(CollectionKey key) {
if (unownedCollections==null) {
return null;
}
else {
return (PersistentCollection) unownedCollections.remove(key);
}
}
/**
* Get the <tt>BatchFetchQueue</tt>, instantiating one if
* necessary.
*/
public BatchFetchQueue getBatchFetchQueue() {
if (batchFetchQueue==null) {
batchFetchQueue = new BatchFetchQueue(this);
}
return batchFetchQueue;
}
public void clear() {
arrayHolders.clear();
entitiesByKey.clear();
entitiesByUniqueKey.clear();
entityEntries.clear();
entitySnapshotsByKey.clear();
collectionsByKey.clear();
collectionEntries.clear();
if ( unownedCollections != null ) {
unownedCollections.clear();
}
proxiesByKey.clear();
nullifiableEntityKeys.clear();
if ( batchFetchQueue != null ) {
batchFetchQueue.clear();
}
hasNonReadOnlyEntities = false;
}
public boolean hasNonReadOnlyEntities() {
return hasNonReadOnlyEntities;
}
public void setEntryStatus(EntityEntry entry, Status status) {
entry.setStatus(status);
setHasNonReadOnlyEnties(status);
}
private void setHasNonReadOnlyEnties(Status status) {
if ( status==Status.DELETED || status==Status.MANAGED || status==Status.SAVING ) {
hasNonReadOnlyEntities = true;
}
}
public void afterTransactionCompletion() {
// Downgrade locks
Iterator iter = entityEntries.values().iterator();
while ( iter.hasNext() ) {
( (EntityEntry) iter.next() ).setLockMode(LockMode.NONE);
}
}
/**
* Get the current state of the entity as known to the underlying
* database, or null if there is no corresponding row
*/
public Object[] getDatabaseSnapshot(Serializable id, EntityPersister persister)
throws HibernateException {
EntityKey key = new EntityKey( id, persister, session.getEntityMode() );
Object cached = entitySnapshotsByKey.get(key);
if (cached!=null) {
return cached==NO_ROW ? null : (Object[]) cached;
}
else {
Object[] snapshot = persister.getDatabaseSnapshot( id, session );
entitySnapshotsByKey.put( key, snapshot==null ? NO_ROW : snapshot );
return snapshot;
}
}
public Object[] getNaturalIdSnapshot(Serializable id, EntityPersister persister)
throws HibernateException {
if ( !persister.hasNaturalIdentifier() ) {
return null;
}
// if the natural-id is marked as non-mutable, it is not retrieved during a
// normal database-snapshot operation...
int[] props = persister.getNaturalIdentifierProperties();
boolean[] updateable = persister.getPropertyUpdateability();
boolean allNatualIdPropsAreUpdateable = true;
for ( int i = 0; i < props.length; i++ ) {
if ( !updateable[ props[i] ] ) {
allNatualIdPropsAreUpdateable = false;
break;
}
}
if ( allNatualIdPropsAreUpdateable ) {
// do this when all the properties are updateable since there is
// a certain likelihood that the information will already be
// snapshot-cached.
Object[] entitySnapshot = getDatabaseSnapshot( id, persister );
if ( entitySnapshot == NO_ROW ) {
return null;
}
Object[] naturalIdSnapshot = new Object[ props.length ];
for ( int i = 0; i < props.length; i++ ) {
naturalIdSnapshot[i] = entitySnapshot[ props[i] ];
}
return naturalIdSnapshot;
}
else {
return persister.getNaturalIdentifierSnapshot( id, session );
}
}
public Object[] getCachedDatabaseSnapshot(EntityKey key) {
//TODO: assertion failure if NO_ROW
return (Object[]) entitySnapshotsByKey.get(key);
}
/*public void removeDatabaseSnapshot(EntityKey key) {
entitySnapshotsByKey.remove(key);
}*/
public void addEntity(EntityKey key, Object entity) {
entitiesByKey.put(key, entity);
getBatchFetchQueue().removeBatchLoadableEntityKey(key);
}
/**
* Get the entity instance associated with the given
* <tt>EntityKey</tt>
*/
public Object getEntity(EntityKey key) {
return entitiesByKey.get(key);
}
public boolean containsEntity(EntityKey key) {
return entitiesByKey.containsKey(key);
}
/**
* Remove an entity from the session cache, also clear
* up other state associated with the entity, all except
* for the <tt>EntityEntry</tt>
*/
public Object removeEntity(EntityKey key) {
Object entity = entitiesByKey.remove(key);
Iterator iter = entitiesByUniqueKey.values().iterator();
while ( iter.hasNext() ) {
if ( iter.next()==entity ) iter.remove();
}
entitySnapshotsByKey.remove(key);
nullifiableEntityKeys.remove(key);
getBatchFetchQueue().removeBatchLoadableEntityKey(key);
getBatchFetchQueue().removeSubselect(key);
return entity;
}
/**
* Get an entity cached by unique key
*/
public Object getEntity(EntityUniqueKey euk) {
return entitiesByUniqueKey.get(euk);
}
/**
* Add an entity to the cache by unique key
*/
public void addEntity(EntityUniqueKey euk, Object entity) {
entitiesByUniqueKey.put(euk, entity);
}
/**
* Retreive the EntityEntry representation of the given entity.
*
* @param entity The entity for which to locate the EntityEntry.
* @return The EntityEntry for the given entity.
*/
public EntityEntry getEntry(Object entity) {
return (EntityEntry) entityEntries.get(entity);
}
/**
* Remove an entity entry from the session cache
*/
public EntityEntry removeEntry(Object entity) {
return (EntityEntry) entityEntries.remove(entity);
}
/**
* Is there an EntityEntry for this instance?
*/
public boolean isEntryFor(Object entity) {
return entityEntries.containsKey(entity);
}
/**
* Get the collection entry for a persistent collection
*/
public CollectionEntry getCollectionEntry(PersistentCollection coll) {
return (CollectionEntry) collectionEntries.get(coll);
}
/**
* Adds an entity to the internal caches.
*/
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,
boolean lazyPropertiesAreUnfetched
) {
addEntity( entityKey, entity );
return addEntry(
entity,
status,
loadedState,
null,
entityKey.getIdentifier(),
version,
lockMode,
existsInDatabase,
persister,
disableVersionIncrement,
lazyPropertiesAreUnfetched
);
}
/**
* Generates an appropriate EntityEntry instance and adds it
* to the event source's internal caches.
*/
public EntityEntry addEntry(
final Object entity,
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,
boolean lazyPropertiesAreUnfetched) {
EntityEntry e = new EntityEntry(
status,
loadedState,
rowId,
id,
version,
lockMode,
existsInDatabase,
persister,
session.getEntityMode(),
disableVersionIncrement,
lazyPropertiesAreUnfetched
);
entityEntries.put(entity, e);
setHasNonReadOnlyEnties(status);
return e;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -