2010-11-23 4 views
8

Ich verwende Persistenz in einem Projekt für die Schule, und ich habe ein Problem, wenn ich versuche zu löschen und zu aktualisieren, funktioniert alle anderen Abfragen.Hibernate illegaler Versuch, eine Sammlung mit zwei offenen Sitzungen zu verknüpfen

Die Ausnahme ist:

Illegal attempt to associate a collection with two open sessions 

Ich schließe jede Sitzung, die ich geöffnet haben.

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

Informationen meine Mapping-Datei von Studenten ist:

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

Und die Hauptzuordnungsdatei:

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

Ich versuche eine Menge Konfiguration, aber ich habe immer die gleiche Ausnahme, wenn jemand eine Idee haben, ich will es!

Danke!

Sorry für mein schlechtes Englisch

+1

Könnten Sie den kompletten Stack-Trace der Ausnahme posten? –

+0

Stack-Trace benötigt! –

+0

mehr Informationen über ur-Code und Projekt-Setup würde auch helfen !! Die Sitzung sollte ständig ausgeführt werden, Details Ihrer DAO + Aktionsdatei/Kontrolle würden hier helfen –

Antwort

4

Die Sitzung ist nicht für einen Anruf verwendet werden soll und geschlossen. Die Verwendung der Dienstprogrammklasse als Basis für Ihr POJO ist keine gute Idee.

Die Entität, die gelöscht wird, sollte die gleiche Sitzung verwenden, von der sie abgerufen oder zumindest in der neuen Sitzung aktualisiert wurde, bevor sie entfernt wird.

Auch die Iteration durch die Entfernung der abhängigen 'Class' Entitäten sollte durch eine Kaskade REMOVE ersetzt werden.

+1

Ich verstehe nicht, warum Leute darauf bestehen, ein DAO über die Persistenzeinheit zu legen. Das nimmt etwas von sich aus Flexibel und steckt es in eine Zwangsjacke. – MikelRascher

+5

Das Einfügen der Persistenzschicht in eine Zwangsjacke ist einer der Hauptgründe, warum Sie ein DAO wollen. Andere sind: Erstellen einer anwendungsspezifischen Persistenzschnittstelle, abstrahierend von der Persistenzschicht, so dass Operationen wie Speichern/Löschen usw. nicht von den Details ihrer Implementierung abhängen. Die Flexibilität in JPA/Hibernate ist gefährlich und sollte nicht missbraucht werden. Im Übrigen ist es für mich eher "kompliziert" als eine komplizierte und sehr schwer zu meisternde API. – zakmck

0

Ich bemerke, dass Sie lazy=false in Ihrer Person Mapping-Datei nicht definiert haben, also nehme ich an, dass Sie Lazy Loading-Attribut für die Eigenschaft Set verwenden. Sie sagen, dass Sie alle Sitzungen geschlossen haben, bevor ein Anruf entfernt werden kann, und dann können Sie auf die Eigenschaft s.getClasses() in der DAOPerson-Methode zugreifen, ohne eine lazyInitializationException zu werfen. Wenn Sie in der Mapping-Datei vergessen haben, lazy=false zu erwähnen, zählen meine Beobachtungen nicht. Wenn das nicht der Fall ist, dann haben Sie sicherlich eine Session geöffnet, an die die Person p (die an die DAO-Entfernungsmethode übergeben wurde) angeschlossen ist. Am Ende dieser Methode erhalten Sie eine Ausnahme, wenn Sie versuchen, das Objekt erneut mit einer anderen Sitzung zu verbinden.

2

für Anfänger Ich denke, es ist eine gute Idee, den Namen, den Sie geben, um das Konzept der Klasse (path persistenceClass.Class) zu refactory. In Java ist "Class" eigentlich eine Klasse. Das könnte in der Zukunft zu einiger Verwüstung führen.

Ein Problem, das ich auf Ihrem DAOPerson Code erkannte, ist, dass es seltsam aussieht. Ich habe verstanden, dass Sie versuchen, den aktuellen Schüler aus seinen Klassen zu entfernen, richtig? wenn ja, versuchen Sie den folgenden Patch auf Ihrem 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) 
} 

nun ein weiteres mögliches Problem: Ihre HibernateUtils behandelt Transaktionen nicht richtig.Sie sollten Ihren Code so umgestalten, dass er wie folgt aussieht:

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

Hoffe, dass hilft!

3

Versuchen Sie mit getCurrentSession() anstelle von openSession() und entfernen Sie die session.close(); Anweisung.

0

Das Problem war auf einen Missbrauch der Kaskadenaktualisierung in einer der Zuordnungen zurückzuführen. Hier ist eine Beispielfeldzuordnung:

Entfernen der Kaskade = CascadeType.ALL das Problem behoben. Fazit: Verwenden Sie Kaskaden-Updates sorgfältig, da Sie dadurch in Schwierigkeiten geraten können. Verwenden Sie es, wenn die Geschäftslogik dies erfordert. In dem Beispiel unten gab es keinen Grund dafür, daher war die Entfernung sowohl geschäftlich als auch programmatisch eine gute Entscheidung.

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

Verwandte Themen