Java Spring-Hibernate:非法尝试将集合与两个打开的会话相关联
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23107944/
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
Spring-Hibernate : Illegal attempt to associate a collection with two open sessions
提问by Dramorian
I am trying to update record in MySql Db. while updating it threw following exception
我正在尝试更新 MySql Db 中的记录。更新时抛出以下异常
org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions
at org.hibernate.collection.AbstractPersistentCollection.setCurrentSession(AbstractPersistentCollection.java:410)
at org.hibernate.event.def.OnUpdateVisitor.processCollection(OnUpdateVisitor.java:43)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:101)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:61)
at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:55)
at org.hibernate.event.def.AbstractVisitor.process(AbstractVisitor.java:123)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:293)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:223)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:89)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:495)
at com.tcs.ignite.ih.spring.dao.UserDAOImpl.saveUpdateUserbean(UserDAOImpl.java:185)
at com.tcs.ignite.ih.spring.dao.UserDAOImpl.blockuser(UserDAOImpl.java:204)
at com.tcs.ignite.ih.spring.service.UserServiceImpl.blockUser(UserServiceImpl.java:187)
at com.tcs.ignite.ih.spring.controller.AdminHomeController.BlockUser(AdminHomeController.java:48)
I check for the session. Its closes in Finally block of every methode . Not able to figure out what is wrong. I am able to to insertupdate opertion with other methods without any problem but only saveUpdateUserBean method is throwing exception
我检查会话。它在每个方法的 finally 块中关闭。无法弄清楚出了什么问题。我可以使用其他方法插入更新操作没有任何问题,但只有 saveUpdateUserBean 方法抛出异常
UserDAOImpl:
用户DAOImpl:
import com.tcs.ignite.ih.hibernate.model.Userdetails;
import com.tcs.ignite.ih.hibernate.model.Userlog;
import com.tcs.ignite.ih.hibernate.model.Userrole;
import com.tcs.ignite.ih.spring.bean.LoginBean;
import com.tcs.ignite.ih.spring.util.LogFile;
import java.util.List;
import org.hibernate.Hibernate;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
@Repository
@Transactional
public class UserDAOImpl implements UserDAO {
@Autowired
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public Userdetails getUserDetails(String username) {
Session session = getSessionFactory().openSession();
Userdetails u = null;
try {
u = (Userdetails) getSessionFactory().openSession()
.createCriteria(Userdetails.class)
.add(Restrictions.eq("email", username)).uniqueResult();
} catch (Exception e) {
LogFile.log.error("UserDAO getuserDetails(): " + e.toString());
} finally {
if (session.isOpen()) {
session.close();
}
return u;
}
}
@Override
public boolean saveUpdateUserbean(Userdetails u) {
Session session = getSessionFactory().openSession();
Transaction tr = session.beginTransaction();
boolean y = false;
try {
session.saveOrUpdate(u);
tr.commit();
y = true;
} catch (Exception e) {
tr.rollback();
e.printStackTrace();
} finally {
if (session.isOpen()) {
session.close();
}
return y;
}
}
@Override
public boolean blockuser(String email) {
Userdetails u = this.getUserDetails(email);
return this.saveUpdateUserbean(u);
}
}
ServiceImpl:
服务实现:
import com.tcs.ignite.ih.hibernate.model.Userdetails;
import com.tcs.ignite.ih.hibernate.model.Userlog;
import com.tcs.ignite.ih.spring.bean.LogBean;
import com.tcs.ignite.ih.spring.bean.RegisterBean;
import com.tcs.ignite.ih.spring.bean.UserBean;
import com.tcs.ignite.ih.spring.bean.loadUserBean;
import com.tcs.ignite.ih.spring.dao.UserDAO;
import com.tcs.ignite.ih.spring.util.Time;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserDAO dao;
@Override
public boolean blockUser(String email) {
return dao.blockuser(email);
}
}
applicationContext.xml:
应用上下文.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="classpath:jdbc.properties" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"/>
<!-- ADD PERSISTENCE SUPPORT HERE (jpa, hibernate, etc) -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.tcs.ignite.ih.hibernate.model" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven />
</beans>
I am able to perform all database operation using same configuration but when i am calling blockuser() method from serviceImpl its calling DAO methods and the saveupdateUserBean is throwing above exception? m i missing anything?
我能够使用相同的配置执行所有数据库操作,但是当我从 serviceImpl 调用 blockuser() 方法时,它的调用 DAO 方法和 saveupdateUserBean 抛出异常?我错过了什么?
回答by NimChimpsky
Use the built-in session tool:
使用内置会话工具:
sessionFactory.getCurrentSession()
Don't manually open and close them yourself.
不要自己手动打开和关闭它们。
The collection is attempting to be associated with two sessions. Also SessionFactory
, although perfectly valid, is not part of JPA. JPA relies on EntityFactory
.
该集合正试图与两个会话相关联。此外SessionFactory
,虽然完全有效,但不是 JPA 的一部分。JPA 依赖于EntityFactory
.
Your methods, because you define the class as transactional, do not require manuallystarting a transaction. Remove this (and any reference to transactions) from saveorUpdate
.
您的方法,因为您将类定义为事务性,不需要手动启动事务。从saveorUpdate
.
Transaction tr = session.beginTransaction();
Transactionsconventionally go on the service layer, not the repositories. So you can wrap multiple repository/DAO calls in one service layer method that is transactional.
交易通常在服务层进行,而不是存储库。因此,您可以将多个存储库/DAO 调用包装在一个事务性的服务层方法中。
回答by Naveen
problem might if u use below code
如果您使用以下代码,可能会出现问题
instead of using getSession()
if you use `
而不是使用,getSession()
如果你使用`
getHibernateTemplate().getSessionFactory().openSession()
, causes two sessions to be opened at the sametime.
getHibernateTemplate().getSessionFactory().openSession()
, 导致同时打开两个会话。
回答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/
回答by D.Zhur.
Hibernate manual says:
休眠手册说:
Use update() if you are certain that the session does not contain an already persistent instance with the same identifier. Use merge()if you want to merge your modifications at any time without consideration of the state of the session. In other words, update() is usually the first method you would call in a fresh session, ensuring that the reattachment of your detached instances is the first operation that is executed.
如果您确定会话不包含具有相同标识符的已持久实例,请使用 update()。如果您想在不考虑会话状态的情况下随时合并修改,请使用 merge()。换句话说,update() 通常是您在新会话中调用的第一个方法,以确保重新附加分离的实例是执行的第一个操作。
It helped in my case. DAO:
它对我有帮助。道:
public void updateUser(User user) throws UserException {
sessionFactory.getCurrentSession().merge(user);
}
POJO Ads (One User has many ads):
POJO 广告(一个用户有多个广告):
@OneToMany(mappedBy = "oUser", fetch = FetchType.LAZY)
public List<Ad> getAoAdList() {
return aoAdList;
}
回答by Diana
I had a similar issue as you and I found no solution to my specific Problem. I had to close the Session on the collection manually with:
我和你有类似的问题,但我没有找到解决我的具体问题的方法。我不得不手动关闭集合上的会话:
((PersistentSet)myObject.getCollection()).getSession().close();
I guess it is not good Practice to solve the issue like this, but for me it was the only way.
我想解决这样的问题不是很好的做法,但对我来说这是唯一的方法。
EDIT: Of course this only works on a Set not if the Collection is a List or sth. else...
编辑:当然,这仅适用于集合,不适用于集合是列表或某物。别的...