📄 sessionimpl.java
字号:
//$Id: SessionImpl.java,v 1.59.2.97 2003/11/27 13:24:16 oneovthafew Exp $package net.sf.hibernate.impl;import java.io.IOException;import java.io.InvalidObjectException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.ObjectStreamException;import java.io.Serializable;import java.lang.reflect.Array;import java.sql.Connection;import java.sql.SQLException;import java.util.ArrayList;import java.util.Collection;import java.util.Collections;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Set;import javax.transaction.SystemException;import javax.transaction.TransactionManager;import net.sf.hibernate.AssertionFailure;import net.sf.hibernate.CallbackException;import net.sf.hibernate.Criteria;import net.sf.hibernate.FlushMode;import net.sf.hibernate.Hibernate;import net.sf.hibernate.HibernateException;import net.sf.hibernate.Interceptor;import net.sf.hibernate.JDBCException;import net.sf.hibernate.Lifecycle;import net.sf.hibernate.LockMode;import net.sf.hibernate.MappingException;import net.sf.hibernate.NonUniqueObjectException;import net.sf.hibernate.ObjectDeletedException;import net.sf.hibernate.ObjectNotFoundException;import net.sf.hibernate.PersistentObjectException;import net.sf.hibernate.PropertyValueException;import net.sf.hibernate.Query;import net.sf.hibernate.QueryException;import net.sf.hibernate.ReplicationMode;import net.sf.hibernate.ScrollableResults;import net.sf.hibernate.SessionFactory;import net.sf.hibernate.Transaction;import net.sf.hibernate.TransactionException;import net.sf.hibernate.TransientObjectException;import net.sf.hibernate.UnresolvableObjectException;import net.sf.hibernate.Validatable;import net.sf.hibernate.WrongClassException;import net.sf.hibernate.cache.CacheException;import net.sf.hibernate.cache.CacheConcurrencyStrategy.SoftLock;import net.sf.hibernate.collection.ArrayHolder;import net.sf.hibernate.collection.CollectionPersister;import net.sf.hibernate.collection.PersistentCollection;import net.sf.hibernate.engine.Batcher;import net.sf.hibernate.engine.CacheSynchronization;import net.sf.hibernate.engine.Cascades;import net.sf.hibernate.engine.CollectionSnapshot;import net.sf.hibernate.engine.Key;import net.sf.hibernate.engine.QueryParameters;import net.sf.hibernate.engine.SessionFactoryImplementor;import net.sf.hibernate.engine.SessionImplementor;import net.sf.hibernate.engine.Versioning;import net.sf.hibernate.hql.FilterTranslator;import net.sf.hibernate.hql.QueryTranslator;import net.sf.hibernate.id.IdentifierGenerationException;import net.sf.hibernate.id.IdentifierGeneratorFactory;import net.sf.hibernate.loader.CriteriaLoader;import net.sf.hibernate.loader.SQLLoader;import net.sf.hibernate.persister.ClassPersister;import net.sf.hibernate.persister.Loadable;import net.sf.hibernate.persister.UniqueKeyLoadable;import net.sf.hibernate.proxy.HibernateProxy;import net.sf.hibernate.proxy.HibernateProxyHelper;import net.sf.hibernate.proxy.LazyInitializer;import net.sf.hibernate.type.AbstractComponentType;import net.sf.hibernate.type.PersistentCollectionType;import net.sf.hibernate.type.Type;import net.sf.hibernate.type.TypeFactory;import net.sf.hibernate.util.ArrayHelper;import net.sf.hibernate.util.IdentityMap;import net.sf.hibernate.util.JoinedIterator;import net.sf.hibernate.util.StringHelper;import org.apache.commons.collections.SequencedHashMap;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;/** * Concrete implementation of a Session, and also the central, organizing component * of Hibernate's internal implementation. As such, this class exposes two interfaces; * Session itself, to the application, and SessionImplementor, to other components * of Hibernate. * * This is where all the hard work goes on. * * NOT THREADSAFE * * @author Gavin King */public final class SessionImpl implements SessionImplementor { private static final Log log = LogFactory.getLog(SessionImpl.class); private SessionFactoryImpl factory; private final boolean autoClose; private final long timestamp; private boolean isCurrentTransaction; //a bit dodgy... private boolean closed = false; private FlushMode flushMode = FlushMode.AUTO; private final Map entitiesByKey; //key=Key, value=Object private final Map proxiesByKey; //key=Key, value=HibernateProxy private transient Map entityEntries; //key=Object, value=Entry private transient Map arrayHolders; //key=array, value=ArrayHolder private transient Map collectionEntries; //key=PersistentCollection, value=CollectionEntry private final Map collectionsByKey; //key=CollectionKey, value=PersistentCollection private HashSet nullifiables = new HashSet(); //set of Keys of deleted objects private final HashSet nonExists; private Interceptor interceptor; private transient Connection connection; private transient boolean connect; // We keep scheduled insertions, deletions and updates in collections // and actually execute them as part of the flush() process. Actually, // not every flush() ends in execution of the scheduled actions. Auto- // flushes initiated by a query execution might be "shortcircuited". // Object insertions and deletions have list semantics because they // must happen in the right order so as to respect referential integrity private transient ArrayList insertions; private transient ArrayList deletions; // updates are kept in a Map because successive flushes might need to add // extra, new changes for an object that is already scheduled for update. // Note: we *could* treat updates the same way we treat collection actions // (discarding them at the end of a "shortcircuited" auto-flush) and then // we would keep them in a list private transient ArrayList updates; // Actually the semantics of the next three are really "Bag" // Note that, unlike objects, collection insertions, updates, // deletions are not really remembered between flushes. We // just re-use the same Lists for convenience. private transient ArrayList collectionCreations; private transient ArrayList collectionUpdates; private transient ArrayList collectionRemovals; private transient ArrayList executions; // The collections we are currently loading private transient Map loadingCollections; private transient List nonlazyCollections; // A set of entity keys that we predict might be needed for // loading soon private transient Map batchLoadableEntityKeys; //actually, a Set private static final Object MARKER = new Object(); private transient int dontFlushFromFind = 0; //private transient boolean reentrantCallback = false; private transient int cascading = 0; private transient int loadCounter = 0; private transient boolean flushing = false; private transient Batcher batcher; /** * Represents the status of an entity with respect to * this session. These statuses are for internal * book-keeping only and are not intended to represent * any notion that is visible to the _application_. */ static final class Status implements Serializable { private String name; Status(String name) { this.name=name; } public String toString() { return name; } private Object readResolve() throws ObjectStreamException { if ( name.equals(LOADED.name) ) return LOADED; if ( name.equals(DELETED.name) ) return DELETED; if ( name.equals(GONE.name) ) return GONE; if ( name.equals(LOADING.name) ) return LOADING; throw new InvalidObjectException("invalid Status"); } } private static final Status LOADED = new Status("LOADED"); private static final Status DELETED = new Status("DELETED"); private static final Status GONE = new Status("GONE"); private static final Status LOADING = new Status("LOADING"); private static final Status SAVING = new Status("SAVING"); interface Executable { void execute() throws HibernateException; void afterTransactionCompletion(boolean success) throws HibernateException; Serializable[] getPropertySpaces(); } /** * We need an entry to tell us all about the current state * of an object with respect to its persistent state */ static final class EntityEntry implements Serializable { LockMode lockMode; Status status; Serializable id; Object[] loadedState; Object[] deletedState; boolean existsInDatabase; Object version; transient ClassPersister persister; // for convenience to save some lookups String className; boolean isBeingReplicated; EntityEntry( Status status, Object[] loadedState, Serializable id, Object version, LockMode lockMode, boolean existsInDatabase, ClassPersister persister, boolean disableVersionIncrement ) { this.status = status; this.loadedState = loadedState; this.id = id; this.existsInDatabase = existsInDatabase; this.version = version; this.lockMode = lockMode; this.isBeingReplicated = disableVersionIncrement; this.persister = persister; if (persister!=null) className = persister.getClassName(); } } /** * We need an entry to tell us all about the current state * of a collection with respect to its persistent state */ public static final class CollectionEntry implements CollectionSnapshot, Serializable { // collections detect changes made via // their public interface and mark // themselves as dirty boolean dirty; // during flush, we navigate the object graph to // collections and decide what to do with them transient boolean reached; transient boolean processed; transient boolean doupdate; transient boolean doremove; transient boolean dorecreate; // if we instantiate a collection during the flush() process, // we must ignore it for the rest of the flush() transient boolean ignore; // collections might be lazily initialized boolean initialized; // "current" means the reference that was found // during flush() and "loaded" means the reference // that is consistent with the current database // state transient CollectionPersister currentPersister; transient Serializable currentKey; transient CollectionPersister loadedPersister; Serializable loadedKey; // session-start/post-flush persistent state Serializable snapshot; // allow the snapshot to be serialized private String role; CollectionEntry() { this.dirty = true; this.initialized = true; // new collections that get found + wrapped // during flush shouldn't be ignored this.ignore = false; } CollectionEntry(CollectionPersister loadedPersister, Serializable loadedID) { // detached collection wrappers that get found + reattached // during flush shouldn't be ignored this(loadedPersister, loadedID, false); } CollectionEntry(CollectionPersister loadedPersister, Serializable loadedID, boolean ignore) { this.dirty = false; this.initialized = false; this.loadedKey = loadedID; setLoadedPersister(loadedPersister); this.ignore = ignore; } CollectionEntry(CollectionSnapshot cs, SessionFactoryImplementor factory) throws MappingException { this.dirty = cs.getDirty(); this.snapshot = cs.getSnapshot(); this.loadedKey = cs.getKey(); this.initialized = true; // detached collections that get found + reattached // during flush shouldn't be ignored this.ignore = false; setLoadedPersister( factory.getCollectionPersister( cs.getRole() ) ); } private boolean isDirty(PersistentCollection coll) throws HibernateException { if ( dirty || ( !coll.isDirectlyAccessible() && !loadedPersister.getElementType().isMutable() ) ) { return dirty; } else { return !coll.equalsSnapshot( loadedPersister.getElementType() ); } } void preFlush(PersistentCollection collection) throws HibernateException { // if the collection is initialized and it was previously persistent // initialize the dirty flag dirty = ( initialized && loadedPersister!=null && isDirty(collection) ) || ( !initialized && dirty ); //only need this so collection with queued adds will be removed from JCS cache if ( log.isDebugEnabled() && dirty && loadedPersister!=null ) log.debug( "Collection dirty: " + MessageHelper.infoString(loadedPersister, loadedKey) ); doupdate = false; doremove = false; dorecreate = false; reached = false; processed = false; } void postInitialize(PersistentCollection collection) throws HibernateException { initialized = true; snapshot = collection.getSnapshot(loadedPersister); } // called after a *successful* flush void postFlush(PersistentCollection collection) throws HibernateException { if (ignore) { ignore = false; } else { if (!processed) throw new AssertionFailure("Hibernate has a bug processing collections"); loadedKey = currentKey; setLoadedPersister(currentPersister); dirty = false; collection.postFlush(); if ( initialized && ( doremove || dorecreate || doupdate ) ) { snapshot = collection.getSnapshot(loadedPersister); //re-snapshot } } } public boolean getDirty() { return dirty; } public Serializable getKey() { return loadedKey; } public String getRole() { return role; } public Serializable getSnapshot() { return snapshot; } public boolean snapshotIsEmpty() { //TODO: implementation here is non-extensible ... //should use polymorphism return initialized && snapshot!=null && ( ( snapshot instanceof Collection && ( (Collection) snapshot ).size()==0 ) || // if snapshot is a collection ( snapshot instanceof Map && ( (Map) snapshot ).size()==0 ) || // if snapshot is a map ( snapshot.getClass().isArray() && Array.getLength(snapshot)==0 )// if snapshot is an array ); } public void setDirty() { dirty = true; } void setLoadedPersister(CollectionPersister persister) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -