Задать вопрос
@KirylLapouski

Откуда появляется вторая открытая сессия в Hibernate?

Здравствуйте, имеются два POJO-класса.
public class PatienceEntity {
    private int id;
    private String fio;
    private Set disease;
    private Set analysis; //элементы сета типа AnalysisEntity 
}
public class AnalysisEntity {
    private int id;
    private TypeOfAnalysisEntity typeOfAnalys;
    private PatienceEntity patience;
}


Как видно из кода, у каждого класса есть ссылка на другой класс. Dao для этих классов выглядит вот так.
CrudDao - общий родитель для классов
public abstract class CrudDao <ID, T> {
    protected SessionFactory sessionFactory;


    void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public CrudDao(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public void create(T o) {
        Session session;
        try {
            session = sessionFactory.getCurrentSession();
        } catch (HibernateException ex) {
            session = sessionFactory.openSession();
        }

        Transaction transaction = null;

        transaction = session.beginTransaction();

        session.save(o);
        transaction.commit();

    }

    public T read(ID id, Class classToRead) {
        Session session;
        try {
            session = sessionFactory.getCurrentSession();
        } catch (HibernateException ex) {
            session = sessionFactory.openSession();
        }
        Transaction transaction = null;

        transaction = session.beginTransaction();

        T occupiedBedsEntity = (T) session.load(classToRead, Integer.parseInt(id.toString()));
        transaction.commit();

        return occupiedBedsEntity;
    }

    public void update(T o) {
        Session session;
        try {
            session = sessionFactory.getCurrentSession();
        } catch (HibernateException ex) {
            session = sessionFactory.openSession();
        }
        Transaction transaction = null;

        transaction = session.beginTransaction();

        session.update(o);

        transaction.commit();
    }

    public abstract void delete(ID id);

    public abstract List list();
}

AnalysisDao
public class AnalysisDao extends CrudDao<Integer, AnalysisEntity>{


    public AnalysisDao( SessionFactory sessionFactory){
        super(sessionFactory);
    }

    public void delete(Integer id) {
        Session session;
        try {
            session = sessionFactory.getCurrentSession();
        } catch (HibernateException ex) {
            session = sessionFactory.openSession();
        }
        Transaction transaction = null;

        transaction= session.beginTransaction();
           SQLQuery query = session.createSQLQuery("DELETE FROM analysis WHERE id = :analys_id");
            query.addEntity(AnalysisEntity.class);
            query.setParameter("analys_id",id);
            query.executeUpdate();

        transaction.commit();
    }

    public List list(){
        Session session;
        try {
            session = sessionFactory.getCurrentSession();
        } catch (HibernateException ex) {
            session = sessionFactory.openSession();
        }
        Transaction transaction = null;

        transaction= session.beginTransaction();

        List staffEntity =  session.createQuery("FROM AnalysisEntity").list();
        transaction.commit();

        return staffEntity;
    }
}

PatienceDao(почти тоже, что и AnalysisDao)

Mapping xml файлы выглядят вот так:
AnalysisEntity.hbm.xml
<hibernate-mapping default-cascade="all" default-lazy="false">

    <class name="entity.AnalysisEntity" table="analysis" schema="" catalog="medicine">
        <id name="id">
            <column name="id" sql-type="int unsigned" not-null="true"/>
            <generator class="native"/>
        </id>
        <many-to-one name="typeOfAnalys" column="id_type_of_analysis" class="entity.TypeOfAnalysisEntity" />
        <many-to-one name="patience" column="id_patience" class="entity.PatienceEntity"/>
    </class>
</hibernate-mapping>

PatienceEntity.hbm.xml
<hibernate-mapping default-cascade="all" default-lazy="false">

    <class name="entity.PatienceEntity" table="patience" schema="" catalog="medicine">
        <id name="id">
            <column name="id" sql-type="int unsigned" not-null="true"/>
        </id>
        <property name="fio">
            <column name="FIO" sql-type="varchar" length="100" not-null="true"/>
        </property>
        <set name="analysis">
            <key column="id_patience"></key>
            <one-to-many   class="entity.AnalysisEntity"/>
        </set>
        <set name="disease" table="patiente_in_hospital">
            <key column="id_patience"></key>
            <many-to-many column="id_disease" class="entity.DiseaseEntity"/>
        </set>
    </class>
</hibernate-mapping>


Ошибка вылазит на этих строках
AnalysisEntity analysisEntity = AnalysisEntity.class.cast(entity);
                TypeOfAnalysisDao typeOfAnalysisDao = new TypeOfAnalysisDao(Main.getOurSessionFactory());

                TypeOfAnalysisEntity typeOfAnalysisEntity =  typeOfAnalysisDao.read(Integer.parseInt(firstField.getText()), TypeOfAnalysisEntity.class);
                analysisEntity.setTypeOfAnalys(typeOfAnalysisEntity);

                PatienceDao patienceDao  =new PatienceDao(Main.getOurSessionFactory());
                analysisEntity.setPatience(patienceDao.read(Integer.valueOf(lastField.getText()), PatienceEntity.class));

Стек ошибки
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException:
Caused by: org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions. Collection : [entity.PatienceEntity.analysis#1]
	at org.hibernate.collection.internal.AbstractPersistentCollection.setCurrentSession(AbstractPersistentCollection.java:623)
	at org.hibernate.event.internal.OnUpdateVisitor.processCollection(OnUpdateVisitor.java:46)
	at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:104)
	at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:65)
	at org.hibernate.event.internal.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:59)
	at org.hibernate.event.internal.AbstractVisitor.process(AbstractVisitor.java:126)
	at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:293)
	at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:227)
	at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:92)
	at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
	at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:647)
	at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:639)
	at org.hibernate.engine.spi.CascadingActions$5.cascade(CascadingActions.java:218)
	at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:379)
	at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:304)
	at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:146)
	at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:95)
	at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:425)
	at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:249)
	at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:178)
	at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:109)
	at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
	at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:38)
	at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
	at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:32)
	at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
	at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:678)
	at org.hibernate.internal.SessionImpl.save(SessionImpl.java:670)
	at org.hibernate.internal.SessionImpl.save(SessionImpl.java:665)
	at dao.CrudDao.create(CrudDao.java:36)
	at FX.StaffController.handleNewStaff(StaffController.java:204)
	... 62 more

Собственно вопрос: где открывается вторая сессия? Может ли это быть из перекрёстных ссылок классов друг на друга?
  • Вопрос задан
  • 1142 просмотра
Подписаться 1 Простой Комментировать
Пригласить эксперта
Ответы на вопрос 1
jaxtr
@jaxtr
JavaEE/Spring-разработчик
Из твоего кода и появляется - если ты не можешь получить текущую сессию при помощи sessionFactory.getCurrentSession, то ты её создаёшь, но не закрываешь.
Чтобы получить текущую сессию, нужно настроить какую-нибудь реализацию CurrentSessionContext, например ThreadLocalSessionContext.

ИМХО
  • Нет смысла использовать транзакции при чтении
  • Используй аннотации вместо XML, будет значительно проще
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы