-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 posts ] 
Author Message
 Post subject: dirty collection exception when using lock
PostPosted: Wed Nov 29, 2006 5:31 am 
Beginner
Beginner

Joined: Thu Aug 24, 2006 6:01 am
Posts: 49
Location: sophia-antipolis, France
Hi,

I'm reading in a graph using SQL and then constructing my java objects from the
results. I would like to then add the newly instantiated objects to the cache
using lock(). I've included the @Cascade(CascadeType.LOCK) to the associations,
but I'm getting a dirty collection error. It seems that when it looks at the
collection downstreamStatusValues, the OnLockVisitor class determines that
collection is not an instance of PersistentCollection. Can anyone help me
understand what the problem is?

Code:
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@Table(name="SHM_HEALTHVALUE")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@DiscriminatorColumn(
    name="HEALTHTYPE",
    discriminatorType=DiscriminatorType.INTEGER
)
public abstract class HealthValue extends BaseObject {
    protected Collection<HealthStatusValue> downstreamStatusValues;
    @ManyToMany
    @Cascade(CascadeType.LOCK)   
    public Collection<HealthStatusValue> getDownstreamStatusValues() {
        return this.downstreamStatusValues;
    }
}


Code:
Entity
@DiscriminatorValue(HealthType.HEALTH_STATUS_ORDINAL)
public class HealthStatusValue extends HealthValue {

    // the children
    private Collection<HealthStatusValue> upstreamStatusValues;
    private Collection<HealthFactorValue> factorValues;

    @ManyToMany(mappedBy="downstreamStatusValues")
    @Cascade(CascadeType.LOCK)
    public Collection<HealthFactorValue> getFactorValues() {
        return this.factorValues;
    }

    @ManyToMany (mappedBy="downstreamStatusValues")
    @Cascade(CascadeType.LOCK)
    public Collection<HealthStatusValue> getUpstreamStatusValues() {
        return this.upstreamStatusValues;
    }


Code:
@Entity
@DiscriminatorValue(HealthType.HEALTH_FACTOR_ORDINAL)
public class HealthFactorValue extends HealthValue {
}


Hibernate version: 3.2

Full stack trace of any exception that occurs:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'CalcEngineBeanContainer' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'HealthCE' while setting bean property 'ceComponents' with key [2]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'HealthCE' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'GraphManager' while setting bean property 'graphManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'GraphManager' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: reassociated object has dirty collection reference (or an array)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'HealthCE' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'GraphManager' while setting bean property 'graphManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'GraphManager' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: reassociated object has dirty collection reference (or an array)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'GraphManager' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: reassociated object has dirty collection reference (or an array)
Caused by: org.hibernate.HibernateException: reassociated object has dirty collection reference (or an array)
at org.hibernate.event.def.OnLockVisitor.processCollection(OnLockVisitor.java:66)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:101)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:61)
at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:55)
at org.hibernate.event.def.AbstractVisitor.process(AbstractVisitor.java:123)
at org.hibernate.event.def.AbstractReassociateEventListener.reassociate(AbstractReassociateEventListener.java:78)
at org.hibernate.event.def.DefaultLockEventListener.onLock(DefaultLockEventListener.java:59)
at org.hibernate.impl.SessionImpl.fireLock(SessionImpl.java:586)
at org.hibernate.impl.SessionImpl.lock(SessionImpl.java:578)
at com.hp.ov.shm.healthce.dao.hibernate.HealthStatusGraphDaoHibernate.lock(HealthStatusGraphDaoHibernate.java:122)
at com.hp.ov.shm.healthce.impl.GraphManager.init_aroundBody0(GraphManager.java:349)
at com.hp.ov.shm.healthce.impl.GraphManager.init_aroundBody1$advice(GraphManager.java:854)
at com.hp.ov.shm.healthce.impl.GraphManager.init(GraphManager.java:1)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:943)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:905)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:870)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:393)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:257)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:168)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:226)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:115)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:798)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:589)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:389)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:257)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:168)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:226)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:115)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedList(BeanDefinitionValueResolver.java:242)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:119)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:798)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:589)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:389)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:257)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:168)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:254)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:332)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:92)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:77)
at org.springframework.test.AbstractSpringContextTests.loadContextLocations(AbstractSpringContextTests.java:130)
at org.springframework.test.AbstractDependencyInjectionSpringContextTests.loadContextLocations(AbstractDependencyInjectionSpringContextTests.java:224)
at org.springframework.test.AbstractSpringContextTests.getContext(AbstractSpringContextTests.java:110)
at org.springframework.test.AbstractDependencyInjectionSpringContextTests.setUp(AbstractDependencyInjectionSpringContextTests.java:192)
at junit.framework.TestCase.runBare(TestCase.java:128)
at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:69)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:120)
at junit.framework.TestSuite.runTest(TestSuite.java:228)
at junit.framework.TestSuite.run(TestSuite.java:223)
at org.junit.internal.runners.OldTestClassRunner.run(OldTestClassRunner.java:35)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 29, 2006 6:01 am 
Senior
Senior

Joined: Mon Oct 23, 2006 5:12 am
Posts: 141
Location: Galicia, Spain
I think the problem is that the collection you are trying to lock is modified (is not "fresh"), Sometimes this happens because you added some elements to it in another session.

I'll suggest you invoking "session.refresh()" of the "parent" entity before executing the session.lock()

_________________
andresgr (--don't forget to rate)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 29, 2006 6:14 am 
Beginner
Beginner

Joined: Thu Aug 24, 2006 6:01 am
Posts: 49
Location: sophia-antipolis, France
Actually, the objects are not initially in the cache because I used SQL to retrieve the data and then in the code I instantiate and connect all of the objects (it's a graph, or actually, many graphs). After I've loaded and instantiated all of the data, I then want to let the cache manage them. I'm using lock() expressly because supposedly it doesn't do any reconciliation with the database. I know that the objects haven't been modified since I loaded them from the DB.

Also, I'm using a 2nd-level cache because my objects live longer than a session (in fact, they should live the lifetime of the server application).

Basically, I have an application which didn't use the cache at all - it managed the complete lifecycle of all of the objects. I'm exploring how I can still keep the database performance I have currently while using the cache. When I'm operating on a particular graph, I know that I need the whole graph in memory, so I want to load it with SQL, but then I want the cache to manage it. lock() seems to be just the thing, but I can't get it to work.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 29, 2006 6:18 am 
Senior
Senior

Joined: Mon Oct 23, 2006 5:12 am
Posts: 141
Location: Galicia, Spain
Then i suggest you to turn on hibernate logging at the DEBUG level (log4j) and see if the cascade locking is going fine...

_________________
andresgr (--don't forget to rate)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 29, 2006 6:32 am 
Beginner
Beginner

Joined: Thu Aug 24, 2006 6:01 am
Posts: 49
Location: sophia-antipolis, France
The exception happens right away, so there's almost no log to see:

Code:
2006-11-29 10:22:01 [main] DEBUG org.springframework.orm.hibernate3.SessionFactoryUtils - Opening Hibernate Session
2006-11-29 10:22:01 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 4770988530790400
2006-11-29 10:22:01 [main] DEBUG org.hibernate.engine.IdentifierValue - id unsaved-value: null
2006-11-29 10:22:01 [main] DEBUG org.hibernate.event.def.AbstractReassociateEventListener - reassociating transient instance: [domain.HealthStatusValue#4]



I thought that the Cascade with LOCK would take care of persisting all of the associated objects, but it doesn't seem to be working. Is it because I have a graph?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 29, 2006 6:51 am 
Regular
Regular

Joined: Tue May 16, 2006 3:32 am
Posts: 117
If you are fetching the objects by SQL ( why don't you use HQL ?) and constructing the objects yourself, then the collection in these objects would be different from the ones that are fetched by hibernate i.e. in Hibernate's terms these would be 'unwrapped'. Hibernate wraps a collection for effectively tracking the changes to these. So when you lock an object, which Hibernate assumes was fetched by it, it would find its collections to be 'dirty' - unwrapped.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 29, 2006 7:04 am 
Senior
Senior

Joined: Mon Oct 23, 2006 5:12 am
Posts: 141
Location: Galicia, Spain
The cascade lock works fine for me...

The log you posted does not include any exceptions... please post the entire log...

_________________
andresgr (--don't forget to rate)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 29, 2006 7:06 am 
Senior
Senior

Joined: Mon Oct 23, 2006 5:12 am
Posts: 141
Location: Galicia, Spain
Oh, JayeshJ is right. The cascade works for me because i access all objects using hibernate...

_________________
andresgr (--don't forget to rate)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 29, 2006 8:06 am 
Beginner
Beginner

Joined: Thu Aug 24, 2006 6:01 am
Posts: 49
Location: sophia-antipolis, France
I'm using SQL because I wanted to minimize the number of SQL queries (I can use 1 with SQL) and because I'm loading a graph. I tried once to do an HQL query with a fetch join on multiple collections and I couldn't. My 'nodes' can have multiple parents and multiple children and I want to load them all at the same time. Also, the node object has relations to other objects which have already been loaded and I didn't want the HQL to load them again.

It seems to me that in order to use the cache, I MUST use HQL or Criteria. Is there no way to use SQL and the cache?

andresgr: I posted the entire log from the call to the lock() method to the end of the file. I posted the entire exception stack trace in the original post.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 29, 2006 8:13 am 
Senior
Senior

Joined: Mon Oct 23, 2006 5:12 am
Posts: 141
Location: Galicia, Spain
Quote:
Is there no way to use SQL and the cache?


May be you can use SQL to load your graph and then use session.find() or session.load() using the id of the root entity. That would load (querying again the DB of course) only that "subgraph"

_________________
andresgr (--don't forget to rate)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 29, 2006 8:25 am 
Regular
Regular

Joined: Tue May 16, 2006 3:32 am
Posts: 117
I don't think hibernate stores the 'object' as is, in cache. It stores the 'values' from which the object is constructed. You could look into the code and see if you could mimic this behaviour.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 29, 2006 8:37 am 
Beginner
Beginner

Joined: Thu Aug 24, 2006 6:01 am
Posts: 49
Location: sophia-antipolis, France
Making more database calls after so painstakingly crafting my SQL just for cache purposes seems to defeat the purpose. Anyway, I'm coming to the conclusion that we don't need to use caching in our application. The point of caching is to minimize database hits and we've already done that in our code. The cache is not really going to help, and it's only going to add a memory and processing overhead.

I just wanted this to work just in case I ever come across a need to use SQL in conjunction with the cache. There are instances where HQL will not work and SQL will. I'm still looking for Hibernate to support hierarchical queries.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.