[hibernate-issues] [Hibernate-JIRA] Updated: (HHH-2668) Caching Fails with Composite-Ids Containing Nested, Complex Entities

Chris Frohoff (JIRA) noreply at atlassian.com
Fri Mar 5 17:54:48 EST 2010


     [ http://opensource.atlassian.com/projects/hibernate/browse/HHH-2668?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Chris Frohoff updated HHH-2668:
-------------------------------

    Attachment: hibernate-test.zip

We're actually seeing a much more serious manifestation of this issue in our production systems, where composite keyed entities containing an uninitialized proxy are being put into the cache and breaking on a CacheKey hashCode() collision.

This is because the initial put() operation requires only a CacheKey.hashCode() call that does not invoke the entity hashCode() method or initialize the lazy proxy, but an operation with a hashCode() collision requires a CacheKey.hashCode() call and a CacheKey.equals() comparison, that latter of which does invoke the entity equals() method and attempts initialization of the lazy proxy outside it's associated session and throws a "org.hibernate.LazyInitializationException: could not initialize proxy - no Session", crippling the application until the cache is manually flushed. If the CacheKey hashCode() and equals() implementations were at least symmetrical with respect to invoking entity methods, the proxy would either be initialized before the first put(), or would not be initialized by any cache operations.

See attached test project that reproduces the issue.


> Caching Fails with Composite-Ids Containing Nested, Complex Entities
> --------------------------------------------------------------------
>
>                 Key: HHH-2668
>                 URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-2668
>             Project: Hibernate Core
>          Issue Type: Bug
>          Components: caching (L2)
>    Affects Versions: 3.2.4.sp1
>         Environment: Problem is independent of environment or platform and most likely exists in prior versions.
>            Reporter: Juan Osuna
>         Attachments: hibernate-caching-fix.zip, hibernate-test.zip
>
>   Original Estimate: 0 minutes
>  Remaining Estimate: 0 minutes
>
> Description of Failing Test Case Scenario
> Preconditions: An entity class is mapped that uses a composite-id that contains a nested entity class. Only the composite-id class implements equals/hashcode, not the nested entity class. 
> Steps to Reproduce:
> 1.	open session and fetch object using composite-id
> 2.	open new session and fetch same object again using different instance of composite-id but with same identity
> Invalid Postconditions: On second retrieve, Hibernate fails to get the object from the cache and unnecessarily reloads the object. CachKeys containing different instances of the composite-id always fail to be equal even though they have the same persistent identity.
> Attachment Contents
> Code fix is attached as well as a Junit test case that reproduces the problem and validates the fix. The full Hibernate suite was also executed with no impact. 
> Attachment contains:
> New Test Method:
> org.hibernate.test.cache.BaseCacheProviderTestCase.testQueryCacheComplexItem
> New Test Entity Items:
> org\hibernate\test\cache\ComplexItem.hbm.xml
> org.hibernate.test.cache.ComplexItem
> org.hibernate.test.cache.ComplexItemPK
> Code Fix:
> org.hibernate.cache.CacheKey (see FIX comments)
> Problem and Fix Details
> Hibernate generally strives to use persistent identifiers for managing object identity rather than the equals/hashcode methods implemented by entity classes. While it is good practice to implement equals/hashcode, Hibernate does not generally force users to do this. 
> When wrapping a composite-id object, the current implementation of CacheKey fails to recurse through nested complex entities to query for equality based on persistent identity. Instead, when the recursion algorithm hits a complex entity, it invokes equals directly on that entity rather than further recursing through the identifier object.
> Notably, the recursion logic for equals is not symmetrical with the recursion logic for hashcode, which does recurse through identifier objects. So, while CacheKey never invokes hashcode on nested complex entities, it does invoke equals on these entities. 
> A simple fix to this inconsistency is to store the factory parameter passed to CacheKey and later pass that parameter to the overloaded method: 
> Type.isEqual(Object x, Object y, EntityMode entityMode, SessionFactoryImplementor factory).
> This fix restores symmetry to equals and hashcode behavior. By calling this overloaded method, the thread of execution will enter EntityType. isEqual(Object x, Object y, EntityMode entityMode, SessionFactoryImplementor factory), which correctly recurses through complex identifiers.
> Design Principles
> Hibernate should strive to behave predictably even in scenarios where users do not follow best practices. 
> Hibernate should strive to be as forgiving as possible as long there is no negative consequence caused by such forgiveness. 
> Hibernate should behave as consistently as possible. If Hibernate does not generally rely user-implemented equals/hashcode, it is best to avoid exceptions to this rule wherever possible. 
> Possible Future Enhancement
> Mapping composite-ids that contain complex entities can cause deep object graphs to be cached as part of CacheKey. This is unsettling because of it's potential to consume memory unnecessarily and unpredictably. 
> Currently, CacheKey caches the hashcode by recursing through a complex graph of identifier objects. Perhaps, it would also be possible for CacheKey to cache an object graph of identifier objects whose leaves hold primitive values. This would further add symmetry between hashcode and equals and lighten the load for caching composite-ids that hold entity classes.
> Robustly supporting composite-ids that hold complex identifiers seems like a worthwhile design goal. 

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        


More information about the hibernate-issues mailing list