下面列出了怎么用org.hibernate.engine.spi.CollectionKey的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* Add a collection to the cache, with a given collection entry.
*
* @param coll The collection for which we are adding an entry.
* @param entry The entry representing the collection.
* @param key The key of the collection's entry.
*/
private void addCollection(PersistentCollection coll, CollectionEntry entry, Serializable key) {
collectionEntries.put( coll, entry );
final CollectionKey collectionKey = new CollectionKey( entry.getLoadedPersister(), key );
final PersistentCollection old = collectionsByKey.put( collectionKey, coll );
if ( old != null ) {
if ( old == coll ) {
throw new AssertionFailure( "bug adding collection twice" );
}
// or should it actually throw an exception?
old.unsetSession( session );
collectionEntries.remove( old );
// watch out for a case where old is still referenced
// somewhere in the object graph! (which is a user error)
}
}
private void evictCollection(PersistentCollection collection) {
CollectionEntry ce = (CollectionEntry) getSession().getPersistenceContext().getCollectionEntries().remove(collection);
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Evicting collection: %s",
MessageHelper.collectionInfoString( ce.getLoadedPersister(),
collection,
ce.getLoadedKey(),
getSession() ) );
}
if (ce.getLoadedPersister() != null && ce.getLoadedPersister().getBatchSize() > 1) {
getSession().getPersistenceContext().getBatchFetchQueue().removeBatchLoadableCollection(ce);
}
if ( ce.getLoadedPersister() != null && ce.getLoadedKey() != null ) {
//TODO: is this 100% correct?
getSession().getPersistenceContext().getCollectionsByKey().remove(
new CollectionKey( ce.getLoadedPersister(), ce.getLoadedKey() )
);
}
}
/**
* 1. Recreate the collection key to collection map
* 2. rebuild the collection entries
* 3. call Interceptor.postFlush()
*/
protected void postFlush(SessionImplementor session) throws HibernateException {
LOG.trace( "Post flush" );
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
persistenceContext.clearCollectionsByKey();
// the database has changed now, so the subselect results need to be invalidated
// the batch fetching queues should also be cleared - especially the collection batch fetching one
persistenceContext.getBatchFetchQueue().clear();
persistenceContext.forEachCollectionEntry(
(persistentCollection, collectionEntry) -> {
collectionEntry.postFlush( persistentCollection );
if ( collectionEntry.getLoadedPersister() == null ) {
//if the collection is dereferenced, unset its session reference and remove from the session cache
//iter.remove(); //does not work, since the entrySet is not backed by the set
persistentCollection.unsetSession( session );
persistenceContext.removeCollectionEntry( persistentCollection );
}
else {
//otherwise recreate the mapping between the collection and its key
CollectionKey collectionKey = new CollectionKey(
collectionEntry.getLoadedPersister(),
collectionEntry.getLoadedKey()
);
persistenceContext.addCollectionByKey( collectionKey, persistentCollection );
}
}, true
);
}
@Override
public void addUnownedCollection(CollectionKey key, PersistentCollection collection) {
if (unownedCollections==null) {
unownedCollections = new HashMap<>( INIT_COLL_SIZE );
}
unownedCollections.put( key, collection );
}
/**
* Attempt to locate the loading collection given the owner's key. The lookup here
* occurs against all result-set contexts...
*
* @param persister The collection persister
* @param ownerKey The owner key
* @return The loading collection, or null if not found.
*/
public PersistentCollection locateLoadingCollection(CollectionPersister persister, Serializable ownerKey) {
final LoadingCollectionEntry lce = locateLoadingCollectionEntry( new CollectionKey( persister, ownerKey ) );
if ( lce != null ) {
if ( LOG.isTraceEnabled() ) {
LOG.tracef(
"Returning loading collection: %s",
MessageHelper.collectionInfoString( persister, ownerKey, getSession().getFactory() )
);
}
return lce.getCollection();
}
return null;
}
/**
* Locate the LoadingCollectionEntry within *any* of the tracked
* {@link CollectionLoadContext}s.
* <p/>
* Implementation note: package protected, as this is meant solely for use
* by {@link CollectionLoadContext} to be able to locate collections
* being loaded by other {@link CollectionLoadContext}s/{@link ResultSet}s.
*
* @param key The collection key.
* @return The located entry; or null.
*/
LoadingCollectionEntry locateLoadingCollectionEntry(CollectionKey key) {
if ( xrefLoadingCollectionEntries == null ) {
return null;
}
LOG.tracev( "Attempting to locate loading collection entry [{0}] in any result-set context", key );
final LoadingCollectionEntry rtn = xrefLoadingCollectionEntries.get( key );
if ( rtn == null ) {
LOG.tracev( "Collection [{0}] not located in load context", key );
}
else {
LOG.tracev( "Collection [{0}] located in load context", key );
}
return rtn;
}
/**
* 1. Recreate the collection key -> collection map
* 2. rebuild the collection entries
* 3. call Interceptor.postFlush()
*/
protected void postFlush(SessionImplementor session) throws HibernateException {
LOG.trace( "Post flush" );
final PersistenceContext persistenceContext = session.getPersistenceContext();
persistenceContext.getCollectionsByKey().clear();
// the database has changed now, so the subselect results need to be invalidated
// the batch fetching queues should also be cleared - especially the collection batch fetching one
persistenceContext.getBatchFetchQueue().clear();
for ( Map.Entry<PersistentCollection, CollectionEntry> me : IdentityMap.concurrentEntries( persistenceContext.getCollectionEntries() ) ) {
CollectionEntry collectionEntry = me.getValue();
PersistentCollection persistentCollection = me.getKey();
collectionEntry.postFlush(persistentCollection);
if ( collectionEntry.getLoadedPersister() == null ) {
//if the collection is dereferenced, unset its session reference and remove from the session cache
//iter.remove(); //does not work, since the entrySet is not backed by the set
persistentCollection.unsetSession( session );
persistenceContext.getCollectionEntries()
.remove(persistentCollection);
}
else {
//otherwise recreate the mapping between the collection and its key
CollectionKey collectionKey = new CollectionKey(
collectionEntry.getLoadedPersister(),
collectionEntry.getLoadedKey()
);
persistenceContext.getCollectionsByKey().put(collectionKey, persistentCollection);
}
}
}
public final void loadingCollectionKeyNotFound(final CollectionKey arg0) {
super.log.logf(FQCN, (org.jboss.logging.Logger.Level.WARN), null, loadingCollectionKeyNotFound$str(), arg0);
}
public final void loadingCollectionKeyNotFound(CollectionKey arg0) {
super.log.logf(FQCN, Logger.Level.WARN, (Throwable)null, this.loadingCollectionKeyNotFound$str(), arg0);
}
@Override
public PersistentCollection useUnownedCollection(CollectionKey key) {
return ( unownedCollections == null ) ? null : unownedCollections.remove( key );
}
@Override
public PersistentCollection getCollection(CollectionKey collectionKey) {
return collectionsByKey.get( collectionKey );
}
/**
* Retrieve the collection that is being loaded as part of processing this
* result set.
* <p/>
* Basically, there are two valid return values from this method:<ul>
* <li>an instance of {@link org.hibernate.collection.spi.PersistentCollection} which indicates to
* continue loading the result set row data into that returned collection
* instance; this may be either an instance already associated and in the
* midst of being loaded, or a newly instantiated instance as a matching
* associated collection was not found.</li>
* <li><i>null</i> indicates to ignore the corresponding result set row
* data relating to the requested collection; this indicates that either
* the collection was found to already be associated with the persistence
* context in a fully loaded state, or it was found in a loading state
* associated with another result set processing context.</li>
* </ul>
*
* @param persister The persister for the collection being requested.
* @param key The key of the collection being requested.
*
* @return The loading collection (see discussion above).
*/
public PersistentCollection getLoadingCollection(final CollectionPersister persister, final Serializable key) {
final EntityMode em = persister.getOwnerEntityPersister().getEntityMetamodel().getEntityMode();
final CollectionKey collectionKey = new CollectionKey( persister, key, em );
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Starting attempt to find loading collection [{0}]",
MessageHelper.collectionInfoString( persister.getRole(), key ) );
}
final LoadingCollectionEntry loadingCollectionEntry = loadContexts.locateLoadingCollectionEntry( collectionKey );
if ( loadingCollectionEntry == null ) {
// look for existing collection as part of the persistence context
PersistentCollection collection = loadContexts.getPersistenceContext().getCollection( collectionKey );
if ( collection != null ) {
if ( collection.wasInitialized() ) {
LOG.trace( "Collection already initialized; ignoring" );
// ignore this row of results! Note the early exit
return null;
}
LOG.trace( "Collection not yet initialized; initializing" );
}
else {
final Object owner = loadContexts.getPersistenceContext().getCollectionOwner( key, persister );
final boolean newlySavedEntity = owner != null
&& loadContexts.getPersistenceContext().getEntry( owner ).getStatus() != Status.LOADING;
if ( newlySavedEntity ) {
// important, to account for newly saved entities in query
// todo : some kind of check for new status...
LOG.trace( "Owning entity already loaded; ignoring" );
return null;
}
// create one
LOG.tracev( "Instantiating new collection [key={0}, rs={1}]", key, resultSet );
collection = persister.getCollectionType().instantiate(
loadContexts.getPersistenceContext().getSession(), persister, key );
}
collection.beforeInitialize( persister, -1 );
collection.beginRead();
localLoadingCollectionKeys.add( collectionKey );
loadContexts.registerLoadingCollectionXRef( collectionKey, new LoadingCollectionEntry( resultSet, persister, key, collection ) );
return collection;
}
if ( loadingCollectionEntry.getResultSet() == resultSet ) {
LOG.trace( "Found loading collection bound to current result set processing; reading row" );
return loadingCollectionEntry.getCollection();
}
// ignore this row, the collection is in process of
// being loaded somewhere further "up" the stack
LOG.trace( "Collection is already being initialized; ignoring row" );
return null;
}
/**
* Finish the process of collection-loading for this bound result set. Mainly this
* involves cleaning up resources and notifying the collections that loading is
* complete.
*
* @param persister The persister for which to complete loading.
*/
public void endLoadingCollections(CollectionPersister persister) {
final SharedSessionContractImplementor session = getLoadContext().getPersistenceContext().getSession();
if ( !loadContexts.hasLoadingCollectionEntries()
&& localLoadingCollectionKeys.isEmpty() ) {
return;
}
// in an effort to avoid concurrent-modification-exceptions (from
// potential recursive calls back through here as a result of the
// eventual call to PersistentCollection#endRead), we scan the
// internal loadingCollections map for matches and store those matches
// in a temp collection. the temp collection is then used to "drive"
// the #endRead processing.
List<LoadingCollectionEntry> matches = null;
final Iterator itr = localLoadingCollectionKeys.iterator();
while ( itr.hasNext() ) {
final CollectionKey collectionKey = (CollectionKey) itr.next();
final LoadingCollectionEntry lce = loadContexts.locateLoadingCollectionEntry( collectionKey );
if ( lce == null ) {
LOG.loadingCollectionKeyNotFound( collectionKey );
}
else if ( lce.getResultSet() == resultSet && lce.getPersister() == persister ) {
if ( matches == null ) {
matches = new ArrayList<>();
}
matches.add( lce );
if ( lce.getCollection().getOwner() == null ) {
session.getPersistenceContext().addUnownedCollection(
new CollectionKey(
persister,
lce.getKey(),
persister.getOwnerEntityPersister().getEntityMetamodel().getEntityMode()
),
lce.getCollection()
);
}
LOG.tracev( "Removing collection load entry [{0}]", lce );
// todo : i'd much rather have this done from #endLoadingCollection(CollectionPersister,LoadingCollectionEntry)...
loadContexts.unregisterLoadingCollectionXRef( collectionKey );
itr.remove();
}
}
endLoadingCollections( persister, matches );
if ( localLoadingCollectionKeys.isEmpty() ) {
// todo : hack!!!
// NOTE : here we cleanup the load context when we have no more local
// LCE entries. This "works" for the time being because really
// only the collection load contexts are implemented. Long term,
// this cleanup should become part of the "close result set"
// processing from the (sandbox/jdbc) jdbc-container code.
loadContexts.cleanup( resultSet );
}
}
void cleanupCollectionXRefs(Set<CollectionKey> entryKeys) {
for ( CollectionKey entryKey : entryKeys ) {
xrefLoadingCollectionEntries.remove( entryKey );
}
}
@LogMessage(level = WARN)
@Message(value = "In CollectionLoadContext#endLoadingCollections, localLoadingCollectionKeys contained [%s], but no LoadingCollectionEntry was found in loadContexts",
id = 159)
void loadingCollectionKeyNotFound(CollectionKey collectionKey);
/**
* instantiate a collection wrapper (called when loading an object)
*
* @param key The collection owner key
* @param session The session from which the request is originating.
* @param owner The collection owner
* @return The collection
*/
public Object getCollection(Serializable key, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) {
CollectionPersister persister = getPersister( session );
final PersistenceContext persistenceContext = session.getPersistenceContext();
final EntityMode entityMode = persister.getOwnerEntityPersister().getEntityMode();
// check if collection is currently being loaded
PersistentCollection collection = persistenceContext.getLoadContexts().locateLoadingCollection( persister, key );
if ( collection == null ) {
// check if it is already completely loaded, but unowned
collection = persistenceContext.useUnownedCollection( new CollectionKey(persister, key, entityMode) );
if ( collection == null ) {
collection = persistenceContext.getCollection( new CollectionKey(persister, key, entityMode) );
if ( collection == null ) {
// create a new collection wrapper, to be initialized later
collection = instantiate( session, persister, key );
collection.setOwner( owner );
persistenceContext.addUninitializedCollection( persister, collection, key );
// some collections are not lazy:
boolean eager = overridingEager != null ? overridingEager : !persister.isLazy();
if ( initializeImmediately() ) {
session.initializeCollection( collection, false );
}
else if ( eager ) {
persistenceContext.addNonLazyCollection( collection );
}
if ( hasHolder() ) {
session.getPersistenceContext().addCollectionHolder( collection );
}
}
}
if ( LOG.isTraceEnabled() ) {
LOG.tracef( "Created collection wrapper: %s",
MessageHelper.collectionInfoString( persister, collection,
key, session ) );
}
}
collection.setOwner(owner);
return collection.getValue();
}
/**
* Register a loading collection xref.
* <p/>
* This xref map is used because sometimes a collection is in process of
* being loaded from one result set, but needs to be accessed from the
* context of another "nested" result set processing.
* <p/>
* Implementation note: package protected, as this is meant solely for use
* by {@link CollectionLoadContext} to be able to locate collections
* being loaded by other {@link CollectionLoadContext}s/{@link ResultSet}s.
*
* @param entryKey The xref collection key
* @param entry The corresponding loading collection entry
*/
void registerLoadingCollectionXRef(CollectionKey entryKey, LoadingCollectionEntry entry) {
if ( xrefLoadingCollectionEntries == null ) {
xrefLoadingCollectionEntries = new HashMap<CollectionKey,LoadingCollectionEntry>();
}
xrefLoadingCollectionEntries.put( entryKey, entry );
}
/**
* The inverse of {@link #registerLoadingCollectionXRef}. Here, we are done
* processing the said collection entry, so we remove it from the
* load context.
* <p/>
* The idea here is that other loading collections can now reference said
* collection directly from the {@link PersistenceContext} because it
* has completed its load cycle.
* <p/>
* Implementation note: package protected, as this is meant solely for use
* by {@link CollectionLoadContext} to be able to locate collections
* being loaded by other {@link CollectionLoadContext}s/{@link ResultSet}s.
*
* @param key The key of the collection we are done processing.
*/
void unregisterLoadingCollectionXRef(CollectionKey key) {
if ( !hasRegisteredLoadingCollectionEntries() ) {
return;
}
xrefLoadingCollectionEntries.remove( key );
}