[hibernate-issues] [Hibernate-JIRA] Commented: (HSEARCH-961) ObjectNotFoundException not caught in FullTextSession for deleted objects

Anders Soee (JIRA) noreply at atlassian.com
Thu Oct 27 03:44:24 EDT 2011


    [ http://opensource.atlassian.com/projects/hibernate/browse/HSEARCH-961?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=44183#comment-44183 ] 

Anders Soee commented on HSEARCH-961:
-------------------------------------

I did some more digging...

It puzzled me that Session.get() threw an exception when it is just supposed to return null, if the entity is not found.

I found out that this happens if there already exists a proxy for that entity, and one of the ways such a proxy can be created is by calling Session.load().

This means that the following sequence of statements will fail with an exception:
(Assuming that the entity with id 99999 does not exist)

session.load(MyEntity.class, 99999);
session.get(MyEntity.class, 99999);

But neither of the two statements alone will fail.

This led me to the following code in PersistenceContextObjectsInitializer:

{code:java} 
59: //check the persistence context
60: List<EntityInfo> remainingEntityInfos = new ArrayList<EntityInfo>( entityInfos.length );
61: for ( EntityInfo entityInfo : entityInfos ) {
62:     if ( ObjectLoaderHelper.areDocIdAndEntityIdIdentical( entityInfo, session ) ) {
63:	    final boolean isInitialized = HibernateHelper.isInitialized(
64:	        session.load(
65:		    entityInfo.getClazz(), entityInfo.getId()
66:             )
67:         );
{code}

This seems sensible at first sight, but it has some side effects.

* If the entities are lazy, it will create proxies for all of them, making subsequent calls to session.get() fail if the entity no longer exists.
* If the entities are not lazy, it will force immediate load of all of them, one by one, killing performance.

I believe the following code will be more in line with what you actually want, without the same side effects:

{code:java}
//check the persistence context
SessionImplementor sessionImplementor = (SessionImplementor) session;
PersistenceContext persistenceContext = sessionImplementor.getPersistenceContext();
String entityName = session.getSessionFactory().getClassMetadata(entityType).getEntityName();
EntityPersister persister = sessionImplementor.getFactory().getEntityPersister(entityName);

List<EntityInfo> remainingEntityInfos = new ArrayList<EntityInfo>( entityInfos.length );
for ( EntityInfo entityInfo : entityInfos ) {
    if ( ObjectLoaderHelper.areDocIdAndEntityIdIdentical( entityInfo, session ) ) {
        EntityKey entityKey = new EntityKey(entityInfo.getId(), persister, session.getEntityMode());
        final boolean isInitialized = persistenceContext.containsEntity(entityKey);
{code}

I tested the above, and it actually solves my problem.



> ObjectNotFoundException not caught in FullTextSession for deleted objects
> -------------------------------------------------------------------------
>
>                 Key: HSEARCH-961
>                 URL: http://opensource.atlassian.com/projects/hibernate/browse/HSEARCH-961
>             Project: Hibernate Search
>          Issue Type: Bug
>          Components: query
>    Affects Versions: 3.4.1.Final
>         Environment: Hibernate 3.6.7
> EHCache 1.2.4 and 2.4.6 in Read-write mode.
> MS SQL Server 2000
> async indexing.
>            Reporter: Anders Soee
>            Priority: Minor
>             Fix For: 3.4.2, 4.0.0.CR2
>
>
> Experienced behavior:
> 1: Show page with search results.
> 2: Delete one
> 3: Redirect back to the previous search.
> 4: Sometimes (about 1 in 10), the search fails with an ObjecNotFoundException.
> Expected behavior:
> As experienced, minus the exceptions.
> My analysis:
> Since the indexing is asynchronous, there will be a short period, where the search will include the deleted item.
> If the entities where not cached, this should not be a problem, since they would simply not be included in the IN query.
> In this case, however, all the entities are cached by EHCache in read-write mode.
> I have identified the problem to be in SecondLevelCacheObjectsInitializer:
> {code}
> 65: final boolean isIn2LCache = session.getSessionFactory().getCache().containsEntity( entityInfo.getClazz(), entityInfo.getId() );
> 66: if ( isIn2LCache ) {
> 67:     //load the object from the second level cache
> 68:     session.get( entityInfo.getClazz(), entityInfo.getId() );
> 69: }
> {code}
> Line 68 is where the exception occurs.
> It appears that cache.containsEntity() is not a guarantee that the entity can actually be loaded.
> In fact, in EHCache a lock object is placed in the cache when the item is deleted, and never removed again.
> Thus the cache contains "something", just not a loadable entity.
> My suggestion:
> Wrap session.get() with a try-catch block, and ignore ObjectNotFoundException's (and probably EntityNotFoundException too, for JPA).
> My workaround:
> Manually evicting the entity from the 2nd level cache when deleting it.
> Stacktrace:
> org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.jysk.resmgr.model.Resource#5663]
>         at org.hibernate.impl.SessionFactoryImpl$2.handleEntityNotFound(SessionFactoryImpl.java:435)
>         at org.hibernate.event.def.DefaultLoadEventListener.returnNarrowedProxy(DefaultLoadEventListener.java:320)
>         at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:277)
>         at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:152)
>         at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:1090)
>         at org.hibernate.impl.SessionImpl.get(SessionImpl.java:1005)
>         at org.hibernate.impl.SessionImpl.get(SessionImpl.java:998)
>         at org.hibernate.search.query.hibernate.impl.SecondLevelCacheObjectsInitializer.initializeObjects(SecondLevelCacheObjectsInitializer.java:68)
>         at org.hibernate.search.query.hibernate.impl.PersistenceContextObjectsInitializer.initializeObjects(PersistenceContextObjectsInitializer.java:81)
>         at org.hibernate.search.query.hibernate.impl.MultiClassesQueryLoader.executeLoad(MultiClassesQueryLoader.java:135)
>         at org.hibernate.search.query.hibernate.impl.AbstractLoader.load(AbstractLoader.java:72)
>         at org.hibernate.search.query.hibernate.impl.FullTextQueryImpl.list(FullTextQueryImpl.java:208)

--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira

        


More information about the hibernate-issues mailing list