Spring -Hibernate: Illegal attempt to associate a collection with two open sessions

I am trying to update a record in MySql Db. when updating it, the following exception was thrown

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 am checking the session. It closes in the finally block of each method. Unable to understand what is wrong. I can easily insert an operation with other methods, but only the saveUpdateUserBean method throws an exception

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> 

I can perform all database operations using the same configuration, but when I call the blockuser () method from serviceImpl, its calling DAO and saveupdateUserBean methods throw exceptions? I did not miss anything?

+7
java spring-mvc annotations hibernate sessionfactory
source share
5 answers

Hibernate guide says :

Use update () if you are sure that the session does not already contain a persistent instance with the same identifier. Use merge () if you want to merge your changes at any time without considering session state. In other words, update () is usually the first method that you would call in a new session, ensuring that re-linking your individual instances is the first operation that is performed.

In my case, it helped. DAO:

 public void updateUser(User user) throws UserException { sessionFactory.getCurrentSession().merge(user); } 

POJO ads (one user has many ads):

 @OneToMany(mappedBy = "oUser", fetch = FetchType.LAZY) public List<Ad> getAoAdList() { return aoAdList; } 
+12
source share

Use the built-in session tool:

 sessionFactory.getCurrentSession() 

Do not open manually or close them yourself.

The collection is trying to be associated with two sessions. In addition, SessionFactory , although completely correct, is not part of the JPA. JPA relies on EntityFactory .

Your methods, since you define the class as transactional, do not require a manual transaction start. Remove this (and any transaction link) from saveorUpdate .

 Transaction tr = session.beginTransaction(); 

Transactions usually go to the service level, not to the repository. Thus, you can wrap multiple calls to the / DAO repository with a single service level method, which is transactional.

+5
source share

The problem was caused by the improper use of cascading updates in one of the mappings. Here is an example field:

 @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name = "user_id") public User getAuthor() { return author; } 

Removing cascade = CascadeType.ALL fixes the problem. Conclusion: Use cascading updates carefully, as this may cause you problems. Use it when business logic is required. There was no need for it in the example below, so removing it was both a business and a software good solution.

Source: http://blog.tremend.ro/2007/03/05/illegal-attempt-to-associate-a-collection-with-two-open-sessions/

+3
source share

the problem may occur if you use the code below

instead of getSession() if you use `

getHibernateTemplate().getSessionFactory().openSession() , calls two sessions to open over time.

+2
source share

I had a similar problem, since you and I did not find a solution for my specific problem. I had to close the session in the collection manually using

 ((PersistentSet)myObject.getCollection()).getSession().close(); 

I think this is not a good practice to solve a problem like this, but for me it was the only way.

EDIT: Of course, this only works in Set, unless the collection is a list or sth. still...

0
source share

All Articles