web-dev-qa-db-fra.com

Spring-Hibernate: tentative illégale d'associer une collection à deux sessions ouvertes

J'essaie de mettre à jour l'enregistrement dans MySql Db. lors de la mise à jour jeté exception suivante

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)

Je vérifie pour la session. Sa ferme dans Enfin bloc de chaque méthode. Pas capable de comprendre ce qui ne va pas. Je peux insérer une mise à jour d'opération avec d'autres méthodes sans aucun problème, mais seule la méthode saveUpdateUserBean lève une 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>

Je suis capable d'exécuter toutes les opérations de base de données en utilisant la même configuration, mais lorsque j'appelle la méthode blockuser () de serviceImpl, ses méthodes DAO d'appel et le saveupdateUserBean lève une exception? il me manque quelque chose?

8
Dramorian

Hibernate le manuel dit :

Utilisez update () si vous êtes certain que la session ne contient pas de fichier instance déjà persistante avec le même identifiant. Utilise merge () if vous souhaitez fusionner vos modifications à tout moment sans contrepartie de l'état de la session. En d'autres termes, update () est généralement le fichier La première méthode que vous appelez lors d’une nouvelle session en vous assurant que le Le réattachement de vos instances détachées est la première opération qui est réalisé.

Cela m'a aidé dans mon cas. DAO:

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

Annonces POJO (un utilisateur a plusieurs annonces):

@OneToMany(mappedBy = "oUser", fetch = FetchType.LAZY)
public List<Ad> getAoAdList() {
    return aoAdList;
}
13
D.Zhur.

Utilisez l'outil de session intégré:

sessionFactory.getCurrentSession()

Ne les ouvrez pas et ne les fermez pas vous-même manuellement. 

La collection tente d'être associée à deux sessions. De plus, SessionFactory, bien que parfaitement valide, ne fait pas partie de JPA. JPA s'appuie sur EntityFactory.

Vos méthodes, parce que vous définissez la classe comme étant transactionnelle, ne nécessitent pas que manuellement démarre une transaction. Supprimez cela (et toute référence aux transactions) de saveorUpdate.

Transaction tr = session.beginTransaction();

Les transactions se classent généralement dans la couche service, pas dans les référentiels. Vous pouvez donc envelopper plusieurs appels DAO/référentiel dans une seule méthode de couche de service transactionnelle.

6
NimChimpsky

Le problème était dû à une mauvaise utilisation de la mise à jour en cascade dans l'un des mappages. Voici un exemple de mappage de champ:

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

Suppression de la cascade = CascadeType.ALL a résolu le problème ..__ Conclusion: utilisez avec précaution les mises à jour en cascade, car cela pourrait vous causer des problèmes. Utilisez-le lorsque la logique métier l'exige. Dans l'exemple ci-dessous, cela n'était pas nécessaire, donc le supprimer était à la fois une décision commerciale et une bonne décision.

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

3
Lazy Coder

problème pourrait si vous utilisez ci-dessous le code 

au lieu d'utiliser getSession() si vous utilisez `

getHibernateTemplate().getSessionFactory().openSession(), ouvre deux sessions à la même heure.

2
Naveen

J'ai eu un problème similaire à vous et je n'ai trouvé aucune solution à mon problème spécifique. J'ai dû fermer la session sur la collection manuellement avec:

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

Je suppose que ce n’est pas une bonne pratique de résoudre le problème de cette manière, mais pour moi c’était le seul moyen.

EDIT: Bien sûr, cela ne fonctionne que sur un ensemble, pas si la collection est une liste ou une liste. autre...

0
Diana