📄 persistencecontext.java
字号:
// $Id: PersistenceContext.java,v 1.26 2005/04/02 20:33:54 oneovthafew Exp $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.EntityMode;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.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.type.CollectionType;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 <a href="mailto:steve@hibernate.org">Steve Ebersole</a> */public class PersistenceContext implements Serializable { // a possibility for "read-only" sessions would be to use a different // PersistentContext impl that does not track the state of things private static final Log log = LogFactory.getLog( PersistenceContext.class ); public static final Object NO_ROW = new MarkerObject("NO_ROW"); private SessionImplementor session; // Loaded entity instances, by EntityKey private final Map entitiesByKey; // Loaded entity instances, by EntityUniqueKey private final Map entitiesByUniqueKey; // Identity map of EntityEntry instances, by the entity instance private transient Map entityEntries; // Entity proxies, by EntityKey private transient Map proxiesByKey; // Snapshots of current database state for entities // that have *not* been loaded private final Map entitySnapshotsByKey; // Identity map of array holder ArrayHolder instances, by the array instance private transient Map arrayHolders; // Identity map of CollectionEntry instances, by the collection wrapper private transient Map collectionEntries; // Collection wrappers, by the CollectionKey private final Map collectionsByKey; //key=CollectionKey, value=PersistentCollection // Set of EntityKeys of deleted objects private HashSet nullifiableEntityKeys = new HashSet(); // EntityKeys that we have tried to load, and not found in the database private final HashSet nonExistantEntityKeys; // EntityUniqueKeys that we have tried to load, and not found in the database private final HashSet nonExistentEntityUniqueKeys; // properties that we have tried to load, and not found in the database private final 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 transient List nonlazyCollections; // A container for collections we load up when the owning entity is not // yet loaded ... for now, this is purely transient! private transient Map unownedCollections; private transient int cascading = 0; private transient int loadCounter = 0; private transient boolean flushing = false; private boolean hasNonReadOnlyEntities = false; private transient CollectionLoadContext collectionLoadContext; private transient BatchFetchQueue batchFetchQueue; 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; } private static final int INIT_MAP_SIZE = 8; /** * Constructs a PersistentContext, bound to the given session. * * @param session The session "owning" this context. */ public PersistenceContext(SessionImplementor session) { this.session = session; entitiesByKey = new HashMap(INIT_MAP_SIZE); entitiesByUniqueKey = new HashMap(INIT_MAP_SIZE); proxiesByKey = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK); entitySnapshotsByKey = new HashMap(INIT_MAP_SIZE); nonExistantEntityKeys = new HashSet(INIT_MAP_SIZE); nonExistentEntityUniqueKeys = new HashSet(INIT_MAP_SIZE); nullAssociations = new HashSet(INIT_MAP_SIZE); entityEntries = IdentityMap.instantiateSequenced(INIT_MAP_SIZE); collectionEntries = IdentityMap.instantiateSequenced(INIT_MAP_SIZE); collectionsByKey = new HashMap(INIT_MAP_SIZE); arrayHolders = IdentityMap.instantiate(INIT_MAP_SIZE); initTransientState(); } private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { log.trace( "deserializing persistent-context" ); ois.defaultReadObject(); entityEntries = IdentityMap.deserialize( ois.readObject() ); collectionEntries = IdentityMap.deserialize( ois.readObject() ); arrayHolders = IdentityMap.deserialize( ois.readObject() ); initTransientState(); proxiesByKey = new ReferenceMap( ReferenceMap.HARD, ReferenceMap.WEAK ); Map map = ( Map ) ois.readObject(); proxiesByKey.putAll( map ); // we need to reconnect all proxies and collections to this session // the association is transient because serialization is used for // different things. Iterator iter = collectionEntries.entrySet().iterator(); while ( iter.hasNext() ) { try { Map.Entry e = ( Map.Entry ) iter.next(); ( ( PersistentCollection ) e.getKey() ).setCurrentSession( session ); CollectionEntry ce = ( CollectionEntry ) e.getValue(); if ( ce.getRole() != null ) { ce.setLoadedPersister( session.getFactory().getCollectionPersister( ce.getRole() ) ); } } catch (HibernateException he) { throw new InvalidObjectException( he.getMessage() ); } } iter = proxiesByKey.values().iterator(); while ( iter.hasNext() ) { Object proxy = iter.next(); if ( proxy instanceof HibernateProxy ) { ( ( HibernateProxy ) proxy ).getHibernateLazyInitializer().setSession( session ); } else { iter.remove(); //the proxy was pruned during the serialization process } } iter = entityEntries.entrySet().iterator(); while ( iter.hasNext() ) { EntityEntry e = ( EntityEntry ) ( ( Map.Entry ) iter.next() ).getValue(); try { e.setPersister( session.getFactory().getEntityPersister( e.getEntityName() ) ); } catch (MappingException me) { throw new InvalidObjectException( me.getMessage() ); } } } private void writeObject(ObjectOutputStream oos) throws IOException { log.trace( "serializing persistent-context" ); oos.defaultWriteObject(); oos.writeObject( IdentityMap.serialize(entityEntries) ); oos.writeObject( IdentityMap.serialize(collectionEntries) ); oos.writeObject( IdentityMap.serialize(arrayHolders) ); HashMap map = new HashMap(INIT_MAP_SIZE); map.putAll(proxiesByKey); oos.writeObject(map); } private void initTransientState() { nonlazyCollections = new ArrayList(INIT_MAP_SIZE); } public void clear() { arrayHolders.clear(); entitiesByKey.clear(); entitiesByUniqueKey.clear(); entityEntries.clear(); entitySnapshotsByKey.clear(); collectionsByKey.clear(); collectionEntries.clear(); proxiesByKey.clear(); nonExistantEntityKeys.clear(); nullifiableEntityKeys.clear(); nonExistentEntityUniqueKeys.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[] 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 object) { entitiesByKey.put(key, object); 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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -