我正在编写一个简单的项目,一个用Swing编写的业务应用程序,使用Hibernate作为后端。我来自Spring,这给了我简单的方法来使用hibernate和事务。无论如何,我设法让Hibernate工作。昨天,在编写一些代码来从DB中删除bean时,我得到了这个:
org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions
删除代码只是:
Session sess = HibernateUtil.getSession();
Transaction tx = sess.beginTransaction();
try {
tx.begin();
sess.delete(ims);
} catch (Exception e) {
tx.rollback();
throw e;
}
tx.commit();
sess.flush();
我的HibernateUtil.getSession()
是:
public static Session getSession() throws HibernateException {
Session sess = null;
try {
sess = sessionFactory.getCurrentSession();
} catch (org.hibernate.HibernateException he) {
sess = sessionFactory.openSession();
}
return sess;
}
其他详细信息:我从未在代码中关闭hibernate会话,只是关闭应用程序。这是错的吗?为什么我在删除时得到这个(只有那个bean,其他人可以工作),而我没有其他操作(插入,查询,更新)?
我在四处阅读并试图仅在getSession
中修改我的sessionFactory.getCurrentSessionCall()
方法,但我得到了:org.hibernate.HibernateException: No CurrentSessionContext configured!
Hibernat conf:
<hibernate-configuration>
<session-factory >
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost/joptel</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">******</property>
<property name="hibernate.connection.pool_size">1</property>
<property name="show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
..mappings..
</session-factory>
</hibernate-configuration>
答案 0 :(得分:53)
我想问你一件事,你为什么要尝试使用“OpenSession”方法?
public static Session getSession() throws HibernateException {
Session sess = null;
try {
sess = sessionFactory.getCurrentSession();
} catch (org.hibernate.HibernateException he) {
sess = sessionFactory.openSession();
}
return sess;
}
您不必调用openSession()
,因为getCurrentSession()
方法总是返回当前会话(如果您将其配置为线程,则为Thread)。
我明白了!... 您必须在hibernate.cfg.xml文件中指定当前上下文
它应该是:
<property name="hibernate.current_session_context_class">thread</property>
答案 1 :(得分:10)
未配置CurrentSessionContext
阅读Contextual Sessions上的参考指南。您需要configure some provided or custom strategy。在hibernate.cfg.xml中,您可以使用
进行配置<property name="hibernate.current_session_context_class">...</property>
您可能希望使用“thread”作为获取每线程会话的值。使用Spring时,它会自动将其设置为SpringSessionContext,从而允许Spring轻松地将Hibernate与其事务管理框架集成。
我来自Spring,这给了我简单的方法来使用hibernate和事务。
如果您熟悉Spring,为什么不使用它来管理Hibernate?你必须已经知道它是多么简单和万无一失。
我从不关闭代码中的hibernate会话,只是关闭应用程序。这是错的吗?
是的,这是非常错误的。每个未关闭的会话都是一个开放的数据库连接,因此您的应用程序当前正在大量连接。
非法尝试将集合与两个开放会话相关联
这正是它所说的。您尝试对已经与其他会话关联的内容执行一些持久性操作(save(),update(),delete())。当你随机地随机打开新会话时会发生这种情况,这就是发生的事情,因为当没有设置“当前会话上下文”时,SessionFactory.getCurrentSession()将始终失败。一般来说,从不打开一个会话只是因为一个人还没有。您需要有明确定义的策略来打开和关闭会话,并且永远不要让任何事情在这些“策略”之外打开会话。这是您遇到的资源泄漏和错误的可靠途径。
答案 2 :(得分:3)
当我在一个门户网站上工作时,我遇到了同样的问题,我正在使用带有hibernate的spring remoting。 只有当被调用的服务方法包含多个使用hibernate会话命中数据库的DAO调用时,才会出现这种问题。
解决方案是为具有多个DAO调用的方法设置@Transaction注释。 (意味着在此方法中所有DOA调用都应该在一个事务中。)