我在学校的项目中使用持久性,当我尝试删除和更新对象时,我遇到了问题,所有其他查询都有效。
例外是:
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>
我尝试了很多配置,但我每次都有相同的例外,如果有人有想法,我想要它!
谢谢!
抱歉我的英文不好
答案 0 :(得分:4)
该会话不适用于一个呼叫并已关闭。使用实用程序类作为POJO的基础不是一个好主意。
要删除的实体应使用从中检索的相同会话,或至少在删除之前刷新新会话。
同样,通过删除依赖的“Class”实体的迭代应该用级联REMOVE替换。
答案 1 :(得分:3)
尝试使用getCurrentSession()
代替openSession()
并删除session.close();
声明。
答案 2 :(得分:2)
对于初学者我认为重构你给出的Class(path persistenceClass.Class)概念的名称是一个好主意。在java世界中,“Class”实际上是一个类。这可能会在未来造成一些破坏。
我在你的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.
}
}
希望有所帮助!
答案 3 :(得分:0)
我注意到你没有在你的人物映射文件中定义lazy=false
,所以我假设你正在使用属性Set的延迟加载属性。您说在删除电话之前已经关闭了所有会话,那么为什么如何在s.getClasses()
remove()
方法中访问该媒体资源DAOPerson
而不会抛出lazyInitializationException
。如果您忘记在映射文件中提及lazy=false
,那么我的观察结果就不算数了。如果不是这种情况,那么你肯定会在Person p(传递给DAO remove方法)的某个地方打开一个会话。在此方法结束时,当您尝试使用另一个会话重新附加对象时,会出现异常。
答案 4 :(得分:0)
问题是由于在其中一个映射中误用了级联更新。这是一个示例字段映射:
@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/