Java 休眠非法尝试将集合与两个打开的会话相关联
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4260310/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
hibernate illegal attempt to associate a collection with two open sessions
提问by Geotinc
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
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 :
DAOP人:
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
对不起,我的英语不好
回答by MikelRascher
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.
会话不打算用于一次呼叫并关闭。使用实用程序类作为 POJO 的基础并不是一个好主意。
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.
此外,迭代删除依赖的“类”实体应替换为级联 REMOVE。
回答by Satadru Biswas
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.
我注意到你没有lazy=false
在你的个人映射文件中定义,所以我假设你正在为属性集使用延迟加载属性。你说你要删除一个电话之前已经结束的所有会话,那么你是怎么来能够访问属性s.getClasses()
的remove()
方法DAOPerson
没有抛lazyInitializationException
。如果你忘记lazy=false
在映射文件中提及,那么我的观察就不算数。如果不是这种情况,那么您肯定会在与 Person p(传递给 DAO 的 remove 方法)关联的某个地方打开一个会话。在此方法结束时,当您尝试使用另一个会话重新附加对象时,您会收到异常。
回答by Lucas de Oliveira
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.
对于初学者,我认为重构您为类(路径持久类.Class)的概念赋予的名称是个好主意。在 Java 世界中,“Class”实际上是一个类。这可能会在未来造成一些破坏。
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:
我在您的 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)
}
Now another possible problem: your HibernateUtils is not treating transactions properly. You should refactor your code to look like the following:
现在另一个可能的问题是:您的 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.
}
}
Hope that helps!
希望有帮助!
回答by SJ.Jafari
Try using getCurrentSession()
instead of openSession()
and remove the session.close();
statement.
尝试使用getCurrentSession()
而不是openSession()
并删除session.close();
语句。
回答by Lazy Coder
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.
删除级联 = CascadeType.ALL 解决了这个问题。结论:小心使用级联更新,因为它可能会给您带来麻烦。当业务逻辑需要时使用它。在下面的示例中,不需要它,因此删除它既是业务上的,也是编程上的一个很好的决定。
Source: http://blog.tremend.ro/2007/03/05/illegal-attempt-to-associate-a-collection-with-two-open-sessions/
资料来源:http: //blog.tremend.ro/2007/03/05/illegal-attempt-to-associate-a-collection-with-two-open-sessions/