web-dev-qa-db-ja.com

Spring-Hibernate:コレクションを2つの開いているセッションに関連付ける不正な試み

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)

セッションを確認します。その最後は、すべてのmethodeのFinalブロックです。何が悪いのか理解できません。問題なく他のメソッドでinsertupdateオペレーションを挿入できますが、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が上記の例外をスローしています。 m何か足りない?

12
Dramorian

休止状態 手動によると

同じ識別子を持つすでに永続的なインスタンスがセッションに含まれていないことが確実な場合は、update()を使用してください。 セッションの状態を考慮せずにいつでも変更をマージする場合は、merge()を使用します。つまり、update()は通常、新しいセッションで呼び出す最初のメソッドであり、デタッチされたインスタンスの再アタッチが最初に実行される操作であることを確認します。

それは私の場合に役立ちました。 DAO:

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

POJO広告(1人のユーザーが多くの広告を持っている):

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

組み込みのセッションツールを使用します。

sessionFactory.getCurrentSession()

手動で開いたり閉じたりしないでください。

コレクションを2つのセッションに関連付けようとしています。また、SessionFactoryは完全に有効ですが、JPAの一部ではありません。 JPAはEntityFactoryに依存しています。

メソッドは、クラスをトランザクションとして定義するため、トランザクションを開始する手動でする必要はありません。これ(およびトランザクションへの参照)をsaveorUpdateから削除します。

Transaction tr = session.beginTransaction();

Transactions 従来は、リポジトリではなくサービス層に移動します。したがって、トランザクション対応の1つのサービスレイヤーメソッドで複数のリポジトリ/ DAO呼び出しをラップできます。

6
NimChimpsky

この問題は、マッピングの1つでカスケード更新が誤って使用されたことが原因でした。次にフィールドマッピングの例を示します。

@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
Lazy Coder

以下のコードを使用すると問題が発生する可能性があります

を使用する場合、getSession()の代わりに `

getHibernateTemplate().getSessionFactory().openSession()、2つのセッションが同時に開かれるようにします。

2
Naveen

私はあなたと同様の問題があり、私の特定の問題に対する解決策は見つかりませんでした。コレクションのセッションを手動で閉じる必要がありました:

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

このような問題を解決することは良い習慣ではないと思いますが、私にとってはそれが唯一の方法でした。

編集:もちろん、これはセットでのみ機能し、コレクションがリストまたはsthの場合は機能しません。そうしないと...

0
Diana