незаконная попытка гибернации связать коллекцию с двумя открытыми сессиями - PullRequest
8 голосов
/ 23 ноября 2010

Я использую постоянство в проекте для школы и у меня возникает проблема, когда я пытаюсь удалить и обновить объект, все остальные запросы работают.

Исключение составляет:

Illegal attempt to associate a collection with two open sessions

Я закрываю каждую сессию, которую открыл.

Код HibernateUtils

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);
}

Для информации, мой картографический файл студентов:

 <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>

И основной файл сопоставления:

<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>

Я пробую много настроек, но у меня всегда одно и то же исключение, если у кого-то есть идея, я хочу!

Спасибо!

Извините за мой плохой английский

Ответы [ 5 ]

4 голосов
/ 14 марта 2011

Сессия не предназначена для одного вызова и закрыта.Использование служебного класса в качестве основы для вашего POJO не очень хорошая идея.

Удаляемый объект должен использовать тот же сеанс, из которого он был получен, или, по крайней мере, обновляться в новом сеансе перед удалением.

Также итерацию по удалению зависимых объектов 'Class' следует заменить каскадом REMOVE.

3 голосов
/ 19 марта 2011

Попробуйте использовать getCurrentSession() вместо openSession() и удалите оператор session.close();.

2 голосов
/ 16 марта 2011

для начала Я думаю, что это хорошая идея для рефакторинга имени, которое вы даете концепции Class (path persistenceClass.Class).В мире Java «Класс» на самом деле класс.Это может привести к хаосу в будущем.

Одна проблема, которую я понял в вашем коде DAOPerson, заключается в том, что он выглядит странно.Я понял, что вы пытаетесь удалить текущего ученика из его классов, правильно?если это так, попробуйте следующее исправление в своем коде:

 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)
 }

Теперь еще одна возможная проблема: ваш HibernateUtils не обрабатывает транзакции должным образом.Вы должны реорганизовать свой код так, чтобы он выглядел следующим образом:

//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.
  }
}

Надеюсь, это поможет!

0 голосов
/ 19 декабря 2014

Проблема была связана с неправильным использованием каскадного обновления в одном из сопоставлений. Вот пример отображения поля:

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

Удаление каскада = CascadeType.ALL решило проблему. Вывод: осторожно используйте каскадные обновления, так как это может привести к неприятностям. Используйте его, когда этого требует бизнес-логика. В приведенном ниже примере в этом не было необходимости, поэтому удаление было и коммерческим, и программно хорошим решением.

Источник: http://blog.tremend.ro/2007/03/05/illegal-attempt-to-associate-a-collection-with-two-open-sessions/

0 голосов
/ 15 марта 2011

Я заметил, что вы не определили lazy=false в своем файле отображения личности, поэтому я предполагаю, что вы используете атрибут отложенной загрузки для свойства Set. Вы говорите, что закрыли все сеансы перед вызовом на удаление, и почему у вас есть доступ к свойству s.getClasses() в методе remove(), равном DAOPerson, без выброса lazyInitializationException. Если вы забыли упомянуть lazy=false в файле сопоставления, то мои наблюдения не учитываются. Если это не так, то у вас наверняка есть сеанс, открытый где-то, с которым связан Person p (переданный методу удаления DAOs). В конце этого метода, когда вы пытаетесь повторно присоединить объект к другому сеансу, вы получаете исключение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...