Hibernate Books

All times are UTC - 5 hours [ DST ]



Post new topic Reply to topic  [ 25 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: test case: "Found two representations of same collectio
PostPosted: Thu Sep 30, 2004 4:33 pm 
Newbie

Joined: Fri May 07, 2004 2:46 pm
Posts: 5
Hibernate version: 2.1.6

Mapping documents:

Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping package="com.everstream.idg.data">

   <class name="Load" table="LOAD">
      <id name="id" column="LOAD_ID" unsaved-value="0">
         <generator class="sequence">
            <param name="sequence">SEQ_LOAD_ID</param>
         </generator>
      </id>
      <property name="startTime" column="LOAD_START_TIME" not-null="true"/>
      <property name="endTime" column="LOAD_END_TIME" not-null="false"/>
      <property name="type" column="LOAD_TYPE" not-null="true"/>
      <property name="status" column="LOAD_STATUS" not-null="true"/>
      <property name="recordsRead" column="RECORDS_READ" not-null="false"/>
      <property name="recordsWritten" column="RECORDS_WRITTEN" not-null="false"/>
      <property name="recordsWithErrors" column="RECORDS_WITH_ERRORS" not-null="false"/>
      <property name="recordsDiscarded" column="RECORDS_DISCARDED" not-null="false"/>
      <list name="messages" table="LOAD_MSG" lazy="true" cascade="all">
         <key column="LOAD_ID"/>
         <index column="LOAD_MSG_SEQ_NBR"/>
         <composite-element class="LoadMessage">
            <property name="timestamp" column="LOAD_MSG_TIME" not-null="true"/>
            <property name="message" column="LOAD_MSG_TXT" not-null="false"/>
         </composite-element>
      </list>
      <many-to-one name="source" class="Source" column="SOURCE_ID" />
   </class>

</hibernate-mapping>


Code between sessionFactory.openSession() and session.close():

Code:
      Load load = new Load();
      load.setStartTime(new Timestamp(System.currentTimeMillis()));
      load.setType("xxx");
      load.setStatus("xxx");
      load.addMessage("xxx");
      session.save.save(load);
      session.flush();
      session.clear();
      load.addMessage("yyy");
      session.update(load);
      session.flush();


Full stack trace of any exception that occurs:

Code:
com.everstream.s4.database.TransactionException: net.sf.hibernate.HibernateException: Found two representations of same collection: com.everstream.idg.data.Load.messages
   at com.everstream.s4.database.Transaction.completeTransaction(Transaction.java:345)
   at com.everstream.s4.database.Transaction.commit(Transaction.java:110)
   at com.everstream.idg.common.Main.test(Main.java:86)
   at com.everstream.idg.common.Main.main(Main.java:39)
Caused by: net.sf.hibernate.HibernateException: Found two representations of same collection: com.everstream.idg.data.Load.messages
   at net.sf.hibernate.impl.SessionImpl.updateReachableCollection(SessionImpl.java:2870)
   at net.sf.hibernate.impl.FlushVisitor.processCollection(FlushVisitor.java:32)
   at net.sf.hibernate.impl.AbstractVisitor.processValue(AbstractVisitor.java:69)
   at net.sf.hibernate.impl.AbstractVisitor.processValues(AbstractVisitor.java:36)
   at net.sf.hibernate.impl.SessionImpl.flushEntity(SessionImpl.java:2592)
   at net.sf.hibernate.impl.SessionImpl.flushEntities(SessionImpl.java:2458)
   at net.sf.hibernate.impl.SessionImpl.flushEverything(SessionImpl.java:2260)
   at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2239)
   at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:61)
   at com.everstream.s4.database.Transaction$SessionResource.commit(Transaction.java:367)
   at com.everstream.s4.database.Transaction.completeTransaction(Transaction.java:304)
   ... 3 more
Exception in thread "main"


Name and version of the database you are using: Oracle 9iR2



This error is occurring solely because I have clear()ed the session, and then reattached (via update()) an object that contains a collection. IMO, this should not be producing an error. I have verified I can work around the problem by issuing a saveOrUpdateCopy(). But the real code is significantly more complex than the above test case, and the DAO that is actually issuing the update() won't have knowledge of whether it needs to issue saveOrUpdateCopy() or just update().

Any thoughts? Is this a real defect, or should Hibernate not handle this type of update()?

-eric


Top
 Profile  
 
 Post subject: works if you do the update in a 2nd session
PostPosted: Thu Sep 30, 2004 5:20 pm 
Newbie

Joined: Fri May 07, 2004 2:46 pm
Posts: 5
FYI, if you perform the update() of the object in a subsequent session, the update will work correctly. It only errs out when you do the update() in the same session in which you have performed a clear() operation.

I've looked through the SessionImpl, but I'm not yet familiar with the code base and can't figure out why the error is being issued. But I strongly feel that this should not be an error condition.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 07, 2004 11:03 pm 
Newbie

Joined: Fri May 07, 2004 2:46 pm
Posts: 5
After letting this problem sit for a while, I found a workaround. I still believe the test case demonstrates a real (if minor) defect with Hibernate, but there is a simple workaround.

The problem is due to the session "seeing" the same collection twice in the same session (which happens when you update() the collection-containing object after clearing the session). So, the solution is to replace the original collection with a new collection:

load.setMessages(new ArrayList(load.getMessages()));

This will cause some extra updates, but it's a very small price to pay in my case. (I'm inserting upwards of 5 million records into the database in a single transaction, which is why I have to clear() the session periodically in the first place.)

Hope someone else may get benefit from this solution.


Top
 Profile  
 
 Post subject: It sure helped me!!
PostPosted: Wed Nov 17, 2004 7:47 am 
Newbie

Joined: Thu Mar 11, 2004 6:44 am
Posts: 3
Location: Milano Italy
Thank you for posting your insight. It would have taken me days to work around this. It does seem like kind of a hack...but a seemingly necessary when loading batches with Hibernate.

Thanks again.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 18, 2005 12:09 pm 
Pro
Pro

Joined: Fri Nov 19, 2004 5:52 pm
Posts: 232
Location: Chicago, IL
I'm running into the same problem. Is this a bug? Calling Session.clear() should clear all objects out of the Session, correct? So, why is it finding and complaining about a duplicate collection?


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 03, 2005 11:42 pm 
Newbie

Joined: Sun Feb 20, 2005 7:07 am
Posts: 4
I face the same problem too.
But it is ok if I do a refresh into my code


----
Something like that, but the following code is not tested.
Code:
      Load load = new Load();
      load.setStartTime(new Timestamp(System.currentTimeMillis()));
      load.setType("xxx");
      load.setStatus("xxx");
      load.addMessage("xxx");
      session.save.save(load);
      session.flush();
      session.clear();
      session.refersh();   ///   Add here
      load.addMessage("yyy");
      session.update(load);
      session.flush();


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 25, 2005 11:03 am 
Newbie

Joined: Mon Apr 25, 2005 11:00 am
Posts: 2
I'm facing this problem too. I still didn't understand what happens...

What does 'refresh into my code' mean? Can you post an example?

Thank you!


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 25, 2005 11:03 am 
Newbie

Joined: Mon Apr 25, 2005 11:00 am
Posts: 2
I'm facing this problem too. I still didn't understand what happens...

What does 'refresh into my code' mean? Can you post an example?

Thank you!


Top
 Profile  
 
 Post subject: key point
PostPosted: Thu Apr 28, 2005 9:13 am 
Newbie

Joined: Tue Apr 26, 2005 4:22 am
Posts: 2
The exception can happen (at least) in such case that:
- Your object have Set field, and
- your code does session.update() after session.clear() //This is the key point

(Sorry, I do not know why Hibernate cannot handle this case better)

So, you can for example solve the problem by
- avoid the above case, or
- after session clear, do session.load() to load a clean object again, or
- close the session after session.update(), then you need to open a new session()

I do not justify these quick solutions well. So, you need to do this by yourself. There are probably some other (better) solutions.

- Peng


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 16, 2005 12:43 am 
Newbie

Joined: Thu Jun 09, 2005 11:11 pm
Posts: 5
I have the same problem with Hibernate 3.0.5
So, I think it's not a bag.
I found one more solution for hibernate 3.0:

Load load = new Load();
load.setStartTime(new Timestamp(System.currentTimeMillis()));
load.setType("xxx");
load.setStatus("xxx");
load.addMessage("xxx");
session.save(load);
session.flush();
session.clear();
load.addMessage("yyy");
session.merge(load);
session.flush();[/b]


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 17, 2005 12:56 pm 
Newbie

Joined: Tue Nov 08, 2005 7:48 am
Posts: 5
I found a JIRA bug for this: http://opensource2.atlassian.com/projec ... se/HHH-511

If you want it fixed - vote for it. At the moment it is marked as Minor but it is pretty Critical for me and I cannot find a way around it at the moment.


Top
 Profile  
 
 Post subject: Caching issue
PostPosted: Tue Dec 20, 2005 12:14 pm 
Beginner
Beginner

Joined: Fri Oct 28, 2005 12:26 pm
Posts: 21
I was running into the caching issue too. I have a HibernateUtility class that handles Hibernate sessions for threads using ThreadLocal variables. Since my server opens a bunch of threads, then leaves them open to service future requests, the cache for one thread would be updated, but all other threads would have old data. As a temporary fix, I added a clear(); to the HibernateUtility class to clear the session every time it was retrieved. That's when I ran into the problem described here (call to update() after call to clear() produces an error). I fixed this by passing the HttpServetRequest into the HibernateUtility class and storing its hash in a ThreadLocal variable. If a session is retrieved twice in the same request, it is only cleared the first time. This may not be the best way, but it's easy and it works!

Oh! Much props to the authors of Hibernate in Action. This is their code. I just modified it slightly for web use.

Code:
package com.idex.hibernate;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

/**
* Basic Hibernate helper class, handles SessionFactory, Session and
* Transaction.
* <p>
* Uses a static initializer for the initial SessionFactory creation and holds
* Session and Transactions in thread local variables. All exceptions are
* wrapped in an unchecked InfrastructureException.
* @author christian@hibernate.org
*/
public class HibernateUtility {

  private static Log log = LogFactory.getLog(HibernateUtility.class);
  private static Configuration configuration;
  private static SessionFactory sessionFactory;
  private static final ThreadLocal<Session> threadSession =
      new ThreadLocal<Session>();
  private static final ThreadLocal<Transaction> threadTransaction =
      new ThreadLocal<Transaction>();
  private static final ThreadLocal<Integer> threadRequestHash =
      new ThreadLocal<Integer>();
  private static final ThreadLocal<Interceptor> threadInterceptor =
      new ThreadLocal<Interceptor>();

  // Create the initial SessionFactory from the default configuration files
  static {
    try {
      configuration = new Configuration();
      sessionFactory = configuration.configure().buildSessionFactory();
      // We could also let Hibernate bind it to JNDI:
      // configuration.configure().buildSessionFactory()
    }
    catch (Throwable ex) {
      // We have to catch Throwable, otherwise we will miss
      // NoClassDefFoundError and other subclasses of Error
      log.error("Building SessionFactory failed.", ex);
      throw new ExceptionInInitializerError(ex);
    }
  }

  /**
   * Returns the SessionFactory used for this static class.
   * @return SessionFactory
   */
  public static SessionFactory getSessionFactory() {
    /*
     * Instead of a static variable, use JNDI: SessionFactory sessions = null;
     * try { Context ctx = new InitialContext(); String jndiName =
     * "java:hibernate/HibernateFactory"; sessions =
     * (SessionFactory)ctx.lookup(jndiName); } catch (NamingException ex) {
     * throw new InfrastructureException(ex); } return sessions;
     */
    return sessionFactory;
  }

  /**
   * Returns the original Hibernate configuration.
   * @return Configuration
   */
  public static Configuration getConfiguration() {
    return configuration;
  }

  /**
   * Rebuild the SessionFactory with the static Configuration.
   */
  public static void rebuildSessionFactory() throws InfrastructureException {
    synchronized (sessionFactory) {
      try {
        sessionFactory = getConfiguration().buildSessionFactory();
      }
      catch (Exception ex) {
        throw new InfrastructureException(ex);
      }
    }
  }

  /**
   * Rebuild the SessionFactory with the given Hibernate Configuration.
   * @param cfg
   */
  public static void rebuildSessionFactory(Configuration cfg)
      throws InfrastructureException {
    synchronized (sessionFactory) {
      try {
        sessionFactory = cfg.buildSessionFactory();
        configuration = cfg;
      }
      catch (Exception ex) {
        throw new InfrastructureException(ex);
      }
    }
  }

  /**
   * Retrieves the current Session local to the thread. <p/> If no Session is
   * open, opens a new Session for the running thread.
   * @return Session
   */
  private static Session getSession(Integer requestHash) {
    Session s = threadSession.get();
    try {
      if (s == null) {
        log.debug("Opening new Session for this thread.");
        if (HibernateUtility.getInterceptor() != null) {
          log.debug("Using interceptor: " + HibernateUtility.getInterceptor().
              getClass());
          s = getSessionFactory().openSession(
              HibernateUtility.getInterceptor());
        }
        else {
          s = getSessionFactory().openSession();
        }
        threadSession.set(s);
      }
    }
    catch (HibernateException ex) {
      throw new InfrastructureException(ex);
    }
    if (threadRequestHash.get() == null) {
      threadRequestHash.set(requestHash);
    }
    else if (requestHash != threadRequestHash.get()) {
      threadRequestHash.set(requestHash);
      s.flush();
      s.clear();
    }
    return s;
  }

  /**
   * Retrieves the current Session local to the thread. <p/> If no Session is
   * open, opens a new Session for the running thread.
   * @return Session
   */
  public static Session getSession(HttpServletRequest request)
      throws InfrastructureException {
    return HibernateUtility.getSession(request.hashCode());
  }

  /**
   * Closes the Session local to the thread.
   */
  public static void closeSession() throws InfrastructureException {
    try {
      Session s = threadSession.get();
      threadSession.set(null);
      if (s != null && s.isOpen()) {
        log.debug("Closing Session of this thread.");
        s.close();
      }
    }
    catch (HibernateException ex) {
      throw new InfrastructureException(ex);
    }
  }

  /**
   * Start a new database transaction.
   */
  public static void beginTransaction() throws InfrastructureException {
    Transaction tx = threadTransaction.get();
    try {
      if (tx == null) {
        log.debug("Starting new database transaction in this thread.");
        tx = getSession(threadRequestHash.get()).beginTransaction();
        threadTransaction.set(tx);
      }
    }
    catch (HibernateException ex) {
      throw new InfrastructureException(ex);
    }
  }

  /**
   * Commit the database transaction.
   */
  public static void commitTransaction() throws InfrastructureException {
    Transaction tx = threadTransaction.get();
    try {
      if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
        log.debug("Committing database transaction of this thread.");
        tx.commit();
      }
      threadTransaction.set(null);
    }
    catch (HibernateException ex) {
      HibernateUtility.rollbackTransaction();
      throw new InfrastructureException(ex);
    }
  }

  /**
   * Commit the database transaction.
   */
  public static void rollbackTransaction() throws InfrastructureException {
    Transaction tx = threadTransaction.get();
    try {
      threadTransaction.set(null);
      if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
        log.debug("Tyring to rollback database transaction of this thread.");
        tx.rollback();
      }
    }
    catch (HibernateException ex) {
      throw new InfrastructureException(ex);
    }
    finally {
      closeSession();
    }
  }

  /**
   * Reconnects a Hibernate Session to the current Thread.
   * @param session The Hibernate Session to be reconnected.
   */
  public static void reconnect(Session session) throws InfrastructureException {
    try {
      session.reconnect();
      threadSession.set(session);
    }
    catch (HibernateException ex) {
      throw new InfrastructureException(ex);
    }
  }

  /**
   * Disconnect and return Session from current Thread.
   * @return Session the disconnected Session
   */
  public static Session disconnectSession() throws InfrastructureException {

    Session session = getSession(threadRequestHash.get());
    try {
      threadSession.set(null);
      if (session.isConnected() && session.isOpen())
        session.disconnect();
    }
    catch (HibernateException ex) {
      throw new InfrastructureException(ex);
    }
    return session;
  }

  /**
   * Register a Hibernate interceptor with the current thread.
   * <p>
   * Every Session opened is opened with this interceptor after registration.
   * Has no effect if the current Session of the thread is already open,
   * effective on next close()/getSession().
   */
  public static void registerInterceptor(Interceptor interceptor) {
    threadInterceptor.set(interceptor);
  }

  private static Interceptor getInterceptor() {
    Interceptor interceptor = threadInterceptor.get();
    return interceptor;
  }

}


Top
 Profile  
 
 Post subject: RE: Found two representations of same collection
PostPosted: Mon Jan 09, 2006 8:29 am 
Newbie

Joined: Sat Apr 30, 2005 10:58 am
Posts: 3
Hi,

i'm facing to the same problem eventhough i'm not clearing the session.

Here is the code snippet :

Code:
            try {
                SnapShot snapShotClone = (SnapShot) BeanUtils.cloneBean(pIdentifiedObject);
                //recursive method to mark all children
                markSnapShot(snapShotClone, pUser, pIdentifiedObject.getId());
                session = snapShotLocalSessionFactoryBean.getSnapShotSessionFactory().openSession();
                transaction = session.beginTransaction();
                session.save(snapShotClone);
                transaction.commit();
                return snapShotClone;
            } catch (Exception e) {
                try {
                    transaction.rollback();
                } catch (Exception e1) {
                    logger.error(e1.getMessage());
                }
                throw new SnapShotException(e);
            } finally {
                try {
                    session.close();
                } catch (Exception e) {
                    logger.error(e.getMessage());
                }
            }



And at stackTrace we can see Session is flushed :

Code:
Caused by: net.sf.hibernate.HibernateException: Found two representations of same collection
   at net.sf.hibernate.impl.SessionImpl.updateReachableCollection(SessionImpl.java:2866)
   at net.sf.hibernate.impl.FlushVisitor.processCollection(FlushVisitor.java:32)
   at net.sf.hibernate.impl.AbstractVisitor.processValue(AbstractVisitor.java:69)
   at net.sf.hibernate.impl.AbstractVisitor.processValues(AbstractVisitor.java:36)
   at net.sf.hibernate.impl.SessionImpl.flushEntity(SessionImpl.java:2588)
   at net.sf.hibernate.impl.SessionImpl.flushEntities(SessionImpl.java:2454)
   at net.sf.hibernate.impl.SessionImpl.flushEverything(SessionImpl.java:2256)
   at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2235)
   at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:61


In Hibernate JIRA, it' s adviced to evict the object but didn' t even loaded it before and din' t called session.clear() !!!

How should i fix this ?

Thank you in advance !


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 25, 2006 6:45 am 
Newbie

Joined: Thu Jan 26, 2006 4:26 am
Posts: 16
If you are using a long session, you can use merge rather than update.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 19, 2006 1:25 am 
Beginner
Beginner

Joined: Mon Jul 03, 2006 5:40 am
Posts: 20
Location: Russia
I have the same blocking problem:
"Found two representations of same collection" on Hibernate 3.1.

I need to create many objects very fast. these objects should be linked to other objects mapped to tables. if the linked entity does not exist, I'm creating a new entity, and then create my main object.
so, I'm trying to use "batch" mode to speed up the process. I'm using this code:
Code:
TestBean test = null;
try {
   test = DBManager.getTest(session,
      suiteBean.getId(), testName);
} catch (ObjectNotFoundException ex1) {
   test = new TestBean(testName);
   session.save(test);
   suiteBean.getTests().add(test);
   session.update(suiteBean);
}
... some code to create "testResultBean" object and linked entities....

session.save(testResultBean);
if (number % JDBC_BATCH_SIZE == 0) {
                           // flush a batch of inserts and release memory:
    session.flush();
    session.clear();
}


and that's what I have:
Quote:
Found two representations of same collection: com....SuiteBean.tests
org.hibernate.HibernateException: Found two representations of same collection: com.....SuiteBean.tests
at org.hibernate.engine.Collections.processReachableCollection(Collections.java:153)
at org.hibernate.event.def.FlushVisitor.processCollection(FlushVisitor.java:37)
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.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:124)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:195)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:76)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:35)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:954)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1526)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:283)
at org.hibernate.impl.CriteriaImpl.uniqueResult(CriteriaImpl.java:305)

is there any Hibernate documentation on this?
I'm using Hibernate 3.1.

the problem dissapears if I remove
Code:
    session.clear();

but then every next N rows insertion speed becomes slower and slower:
e.g. first 50 entities are created in 0.2 sec,
then next 50 entities - 0.4 sec,
then 0.7, etc. the time grows up significantly!
I have to create about 2000 objects in one working cycle, so without clear() operation it works VERY (!) slow when the row index becomes more than, say, 500-800.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 25 posts ]  Go to page 1, 2  Next

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.