开发者

hibernate illegal attempt to associate a collection with two open sessions

I'm using persistence in a project for school, and I have a problem when I'm try to deleting and updating object, all others queries works.

The exception is :

Illegal attempt to associate a collection with two open sessions

I close every session I have opened.

HibernateUtils code

public class Hibernate
{
 protected static final SessionFactory sessionFactory;

 private Session session;

 static 
 {
  try 
  {
   // Create the SessionFactory from hibernate.cfg.xml
   sessionFactory = new Configuration().configure().buildSessionFactory();
   session
  } 
  catch (Throwable ex) 
  {
   // Make sure you log the exception, as it might be swallowed
   System.err.println("Initial SessionFactory creation failed." + ex);
   throw new ExceptionInInitializerError(ex);
  }
 }

 public void create(Object obj)
 {
  this.session = sessionFactory.openSession();
  session.getTransaction().begin();
  session.save(obj);
  session.getTransaction().commit(); 
  session.close();
 }

 public void refresh(Object obj)
 {
  this.session = sessionFactory.openSession();
  session.getTransaction().begin();
  session.refresh(obj);
  session.getTransaction().commit();
  session.close();
 }

 public void update(Object obj)
 {
  this.session = sessionFactory.openSession();
  session.getTransaction().begin();  
  session.saveOrUpdate(obj);
  session.getTransaction().commit();
  session.close();

 }
 public void delete(Object obj)
 {
  this.session = sessionFactory.openSession();
  session.getTransaction().begin();
  session.delete(obj);
  session.flush();
  session.getTransaction().commit();  
  session.close();
 }
 protected String protectString(String toProtect)
 {
  return (toProtect.replace("'", "''"));
 }

}

DAOPerson :

public class DAOPerson extends Hibernate
{

 public void remove(Person p)
 {
  if (p instanceof Student)
  {
   Student s = (Student)p;
   Set<persistenceClass.Class> set = s.getClasses();
   Iterator<persistenceClass.Class> it = set.iterator();
   while (it.hasNext())
   {
    persistenceClass.Class r = it.next();
    r.getStudents().remove(s);
   }
   p.getBirthCountry();
   p.getCountry();
   this.delete(p);
  }
  else
   this.delete(p);
}

For information my mapping file of students is :

 <class name="persistenceClass.Person" table="T_PERSON">
  <id name="Id" column="PERSON_ID">
   <generator class="native" />
  </id>
  <property name="FirstName" column="PERSON_FIRST_NAME" not-null="true" />
  <property name="LastName" column="PERSON_LAST_NAME" not-null="true" />
  <property name="Type" column="PERSON_TYPE" not-null="true" />
  <property name="BirthDate" column="PERSON_BIRTH_DATE" />
  <property name="BirthCity" column="PERSON_BIRTH_CITY" />
  <property name="PhoneNumber" column="PERSON_PHONE_NUMBER" />
  <property name="MobileNumber" column="PERSON_MOBILE_NUMBER" />
  <property name="Mail" column="PERSON_MAIL" />
  <property name="Address" column="PERSON_ADDRESS_ADDRESS" />
  <property name="ZipCode" column="PERSON_ADDRESS_ZIPCODE" />
  <property name="City" column="PERSON_ADDRESS_CITY" />
  <property name="Image" column="PERSON_IMAGE" type="image" />
  <many-to-one name="Country" column="PERSON_ADDRESS_COUNTRY" class="persistenceClass.Country" />
  <many-to-one name="BirthCountry" column="PERSON_BIRTH_COUNTRY" class="persistenceClass.Country" />
  <many-to-one name="Civility" column="PERSON_CIVILITY" class="persistenceClass.Civility" />
  <many-to-one name="Sex" column="PERSON_SEX" class="persistenceClass.Sex" />
  <joined-subclass name="persistenceClass.Student" table="T_STUDENT">
   <key column="PERSON_ID" />
   <set name="Classes" table="T_CLASS_STUDENT" inverse="true" >
    <key column="PERSON_ID" />
    <many-to-many class="persistenceClass.Class" column="CLASS_ID" />  
   </set>
  </joined-subclass>
  <joined-subclass name="persistenceClass.Teacher" table="T_TEACHER">
   <key column="PERSON_ID" />
  </joined-subclass>
 </class>

And the main mapping file :

<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">org.gjt.mm.mysql.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/projet</property>
<property name="connection.username">root</property>
<property name="connection.password"></property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">10</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<!-- Drop and re-create the database schema on start-up, also try with “update”开发者_运维技巧 to keep the previous values -->
<property name="hbm2ddl.auto">update</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<mapping resource="persistenceConfigurations/Person.hbm.xml"/>
<mapping resource="persistenceConfigurations/Country.hbm.xml"/>
<mapping resource="persistenceConfigurations/Civility.hbm.xml"/>
<mapping resource="persistenceConfigurations/Sex.hbm.xml"/>
<mapping resource="persistenceConfigurations/Formation.hbm.xml"/>
<mapping resource="persistenceConfigurations/Year.hbm.xml"/>
<mapping resource="persistenceConfigurations/Class.hbm.xml"/>
<mapping resource="persistenceConfigurations/Subject.hbm.xml"/>
<mapping resource="persistenceConfigurations/Room.hbm.xml"/>
<mapping resource="persistenceConfigurations/Lesson.hbm.xml"/>
</session-factory>
</hibernate-configuration>

I try a lot of configuration but I've everytime the same exception, if somebody have an idea, I want it !

Thanks !

Sorry for my bad english


The session is not meant to be used for one call and closed. Using the utility class as a base for your POJO is not a good idea.

The entity that is being deleted should use the same session that it was retrieved from or at least be refreshed on the new session before being removed.

Also the iterating through the removal of the dependent 'Class' entities should be replaced with a cascade REMOVE.


Try using getCurrentSession() instead of openSession() and remove the session.close(); statement.


for starters I think it's a good idea to refactor the name you are giving to the concept of Class (path persistenceClass.Class). In java world 'Class' is actually a class. That may cause some havoc in the future.

One problem I realized on your DAOPerson code is that it looks strange. I understood you're trying to remove the current student from its classes, correct? if so, try the following patch on your code:

 public void remove(Person p)
 {
  if (p instanceof Student)
  {
   Student s = (Student)p;
   Set<persistenceClass.Class> set = s.getClasses();
   Iterator<persistenceClass.Class> it = set.iterator();
   while (it.hasNext())
    {
     persistenceClass.Class r = it.next();
     r.getStudents().remove(s);

     //now effectively removing the student from the class. 
     //this will update the class and its persistent set of students.
     this.update(r); 
    }
   }
   this.delete(p); //now remove the student (or whatever comes as argument)
 }

Now another possible problem: your HibernateUtils is not treating transactions properly. You should refactor your code to look like the following:

//Example
public void create(Object obj){
  this.session = sessionFactory.openSession();
  try{
    session.getTransaction().begin();
    session.save(obj);
    session.getTransaction().commit();     
  } catch (Exception e) {
    e.printStackTrace();
    session.getTransaction().rollback(); 
  } finally {
    session.flush();
    session.close();
    //keep in mind that too many flushes might cause db memory shortage.
    //So if you are treating list of objects and so on iterate and save them flushing
    //only when your batch size is reached.
  }
}

Hope that helps!


I notice that you haven't defined lazy=false in you person mapping file, so I assume you are using lazy loading attribute for the property Set. You say you have closed all sessions before a call to remove, then how come you are able to access the property s.getClasses() in the remove() method of DAOPerson without throwing a lazyInitializationException. If you forgot to mention lazy=false in the mapping file, then my observations do not count. If that is not the case, then you surely do have a session open somewhere to which the Person p (passed to the DAOs remove method) is associated. At the end of this method, when you try to re-attach the object with another session you get an exception.


The problem was due to a misuse of cascade update in one of the mappings. Here is a sample field mapping:

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = “user_id”)
public User getAuthor() {
return author;
}

Removing the cascade = CascadeType.ALL fixed the problem. Conclusion: carefully use cascade updates as it may get you into trouble. Use it when business logic requires it. In the example below there was no need for it, so removing it was both business and programatically a good decision.

Source: http://blog.tremend.ro/2007/03/05/illegal-attempt-to-associate-a-collection-with-two-open-sessions/

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜