我正在尝试更新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)
我检查会话。它在每个方法的最后块中关闭。无法弄清楚出了什么问题。我可以使用其他方法insertupdate opertion而没有任何问题,但只有saveUpdateUserBean方法抛出异常
在UserDAOImpl:
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 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>
我能够使用相同的配置执行所有数据库操作但是当我从serviceImpl调用blockuser()方法时,它调用DAO方法和saveupdateUserBean抛出异常?我错过了什么?
答案 0 :(得分:13)
休眠manual says:
如果您确定会话不包含,请使用update() 已具有相同标识符的持久化实例。 使用merge() if 您想在不考虑的情况下随时合并您的修改 会议的状态。换句话说,update()通常是 你将在新的会话中调用的第一种方法,确保 重新附加分离的实例是第一个操作 执行。
在我的案例中有所帮助。 DAO:
public void updateUser(User user) throws UserException {
sessionFactory.getCurrentSession().merge(user);
}
POJO广告(一个用户有很多广告):
@OneToMany(mappedBy = "oUser", fetch = FetchType.LAZY)
public List<Ad> getAoAdList() {
return aoAdList;
}
答案 1 :(得分:6)
使用内置会话工具:
sessionFactory.getCurrentSession()
请勿自行手动打开和关闭它们。
该集合正在尝试与两个会话相关联。此外SessionFactory
虽然完全有效,但不属于JPA。 JPA依赖于EntityFactory
。
您的方法,因为您将类定义为事务性,不需要手动启动事务。从saveorUpdate
删除此(以及对交易的任何引用)。
Transaction tr = session.beginTransaction();
传统上,Transactions位于服务层,而不是存储库。因此,您可以在一个事务性的服务层方法中包装多个存储库/ DAO调用。
答案 2 :(得分:3)
问题是由于在其中一个映射中误用了级联更新。这是一个示例字段映射:
@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/
答案 3 :(得分:2)
可能会出现问题
而不是使用getSession()
如果你使用`
getHibernateTemplate().getSessionFactory().openSession()
会导致两个会话同时打开。
答案 4 :(得分:0)
我和你有类似的问题,我找不到解决我特定问题的方法。我不得不手动关闭集合上的Session:
((PersistentSet)myObject.getCollection()).getSession().close();
我想这不是一个很好的解决这个问题的做法,但对我来说这是唯一的方法。
编辑:当然这仅适用于Set,如果Collection是List或sth。其他...
答案 5 :(得分:0)
如果您正在创建或更新包含从不同会话加载的实体的现有记录,就会发生这种情况。该错误具有欺骗性,因为它与触发错误的实体的关系。解决方案是在当前会话中加载一个新实体,并使用它代替从不同会话传入的参数。
entity = getHibernateTemplate().load(MyEntity.class, entity.getId())