Java Spring Hibernate:非法尝试将集合与两个打开的会话关联

Java Spring Hibernate:非法尝试将集合与两个打开的会话关联,java,hibernate,spring-mvc,annotations,sessionfactory,Java,Hibernate,Spring Mvc,Annotations,Sessionfactory,我正在尝试更新MySql数据库中的记录。更新时引发了以下异常 org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions at org.hibernate.collection.AbstractPersistentCollection.setCurrentSession(AbstractPersistentCollection.java:410) at org

我正在尝试更新MySql数据库中的记录。更新时引发了以下异常

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)
我检查会议。它在每个方法的最后一个块中关闭。无法找出问题所在。我能够用其他方法插入更新操作,没有任何问题,但只有saveUpdateUserBean方法抛出异常

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)
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>

org.hibernate.dialogue.mysqldialogue

我能够使用相同的配置执行所有数据库操作,但当我从serviceImpl调用blockuser()方法时,它调用的DAO方法和saveupdateUserBean抛出上述异常?我遗漏了什么吗?

使用内置会话工具:

sessionFactory.getCurrentSession()
不要自己手动打开和关闭它们

集合正试图与两个会话关联。另外,
SessionFactory
,虽然完全有效,但不属于JPA的一部分。JPA依赖于
EntityFactory

由于您将类定义为事务类,因此您的方法不需要手动启动事务。从
saveorUpdate
中删除此项(以及对事务的任何引用)

Transaction tr = session.beginTransaction();

传统上是在服务层,而不是存储库上。所以,您可以将多个存储库/DAO调用封装在一个事务性的服务层方法中。

如果您使用下面的代码,可能会出现问题

如果您使用`


getHibernateTemplate().getSessionFactory().openSession()
,导致两个会话同时打开。

该问题是由于在其中一个映射中滥用级联更新造成的。下面是一个示例字段映射:

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = “user_id”)
public User getAuthor() {
return author;
}
移除cascade=CascadeType.ALL修复了该问题。 结论:小心使用级联更新,因为它可能会给您带来麻烦。在业务逻辑需要时使用它。在下面的示例中,不需要它,因此从业务和编程两方面来说,删除它都是一个好的决定

来源:

休眠:

如果确定会话中不包含更新,请使用update() 已存在具有相同标识符的持久实例如果需要,请使用merge() 您想在任何时候合并您的修改,而不必考虑 会议的状态。换句话说,update()通常是 在新会话中调用的第一个方法,确保 重新连接分离的实例是要执行的第一个操作 执行

这对我很有帮助。 道:

POJO广告(一个用户有多个广告):

@OneToMany(mappedBy=“oUser”,fetch=FetchType.LAZY)
公共列表getAoAdList(){
返回aoAdList;
}

我和你有一个类似的问题,我没有找到解决我具体问题的方法。我必须通过以下方式手动关闭集合上的会话:

((PersistentSet)myObject.getCollection()).getSession().close();
我想这不是解决问题的好办法,但对我来说这是唯一的办法


编辑:当然,这只适用于集合,如果集合是列表或其他内容,则不适用。

请解释一下。我怎样才能隐式打开会话?@igniter嗯,是的,我提前看到了更新。您可以使用注释将类定义为事务性的-无需在代码中打开事务。我是否也需要从这些方法中删除所有事务?如何在没有事务的情况下提交saveupdate?或删除批注。。。只有一个事务是错误的。有不同类型的事务注释。需要新建、只读等。我通常根据需要在每个方法上定义它们。我尝试在没有@Transactional注释的情况下使用它们。但还是有同样的例外。什么时候逻辑需要呢?我的箱子合适吗?因为我没有使用它,我得到了错误:
((PersistentSet)myObject.getCollection()).getSession().close();