代码之家  ›  专栏  ›  技术社区  ›  Jaap Coomans

非法尝试将集合与两个打开的会话相关联

  •  13
  • Jaap Coomans  · 技术社区  · 17 年前

    我正试图在另一个pojo的集合中添加一个pojo。我确信我在某个地方犯了一个非常愚蠢的错误,但我不知道如何解决它。

    我有一个pojo LookupTable,其中包含列列表:

    public class LookupTable {
      private long id;
      // More properties go here...
      private List<Column> columns;
    
      public void addColumn(Column column) {
        this.columns.add(column);
      }
    
      // More methods go here...
    }
    

    在休眠配置中,我有:

    <class name="LookupTable" table="ARR_LOOKUP_TABLE">
      <id name="id" column="ID">
        <generator class="native"/>
      </id>
      <!-- Some properties here -->
      <bag name="columns" cascade="all,delete-orphan" access="field">
        <key column="LOOKUP_TABLE" not-null="true"/>
        <one-to-many class="Column"/>
      </bag>
    </class>
    
    <class name="Column" table="ARR_LOOKUP_COLUMN">
      <id name="id" column="ID">
        <generator class="native"/>
      </id>
      <!-- Some properties here -->
    </class>
    

    在我的Spring配置文件中,我有:

    <tx:advice id="txAdvice" transaction-manager="txManager">
      <tx:attributes>
        <tx:method name="*" propagation="REQUIRED"/>
      </tx:attributes>
    </tx:advice>
    <aop:config>
      <aop:pointcut id="managers" expression="execution(public * com.foo.*Manager.*(..))"/>
      <aop:advisor advice-ref="txAdvice" pointcut-ref="managers"/>
    </aop:config>
    

    最后,在我的管理器类(com.foo.RelookupTableManager)中,这一切都失败了:

    public void addColumnToTable(Column column, long tableId) {
      LookupTable lookupTable = this.lookupTableDao.findById(tableId);
      lookupTable.addColumn(column);
      this.lookupTableDao.saveOrUpdate(lookupTable);
    }
    

    这里的变量lookupTableDao是指一个简单的DAO类,它扩展了HibernateDaoSupport。

    我得到的错误是:

    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.foo.AbstractDao.saveOrUpdate(AbstractDao.java:29)
      at com.foo.LookupTableManager.addColumnToTable(LookupTableManager.java:338)
    ... etc ...
    

    好的,我明白了我得到的基本信息。但我不明白的是,第二次会议在哪里举行。…有人能帮我吗?

    我使用的是Hibernate 3.2.6.ga、Spring 2.5.5和Tomcat 6.0

    7 回复  |  直到 8 年前
        1
  •  5
  •   Rann Lifshitz rul    8 年前

    原来我根本没有交易。我在另一个配置文件中使用了几乎相同的事务配置。

    那边的切入点也被称为“经理”,所以我的顾问在另一个文件中引用了切入点。

    重命名切入点解决了我的问题。

        2
  •  3
  •   Chris Kimpton    17 年前

    我的猜测是 lookupTableDao.findById call正在一个会话中获取您的对象,但 lookupTableDao.saveOrUpdate 是另一个-你怎么得到 Session 对象,通过弹簧?

    在哪里 Column 对象来自-它已经在数据库中了还是新的?

        3
  •  2
  •   Umar    16 年前

    问题出在视图中的打开会话筛选器映射上。 它正在getSession上创建会话 另一个在拯救。

    您只能将singleSession更改为false 默认为true

        4
  •  2
  •   Mark Bakker    14 年前

    显然,使用合并可能会解决这个问题

    myInstance = (myInstanceClass) Session.merge(myInstance);
    
        5
  •  2
  •   Raul Rene    14 年前

    我在以下代码中遇到了同样的问题: 我想更新某个实体商店。我从这个方法中检索它:

    @Override
    public Store getStoreByStoreId(final long storeId) {
        getHibernateTemplate().execute(new HibernateCallback<Store>() {
            @Override
            public StoredoInHibernate(Session session) throws HibernateException, SQLException {
                return (Store) session.createCriteria(Store.class)
                        .add(Restrictions.eq(Store.PROP_ID, storeId))
                        .uniqueResult();
            }
        });
    }
    

    然后,我用以下方法更新商店:

    @Override
    public void updateStoreByStoreId(final long storeId) {
        getHibernateTemplate().execute(new HibernateCallback<Void>() {
            @Override
            public Void doInHibernate(Session session) throws HibernateException, SQLException {
                Store toBeUpdated =  getStoreByStoreId(storeId);
    
                if (toBeUpdated != null){
                    // ..change values for certain fields
                    session.update(toBeUpdated);
                }
                return null;
            }
        });
    } 
    

    原来我收到了“非法尝试…”错误,因为get方法的第一个会话没有关闭,我试图用另一个会话更新存储。对我来说,解决方案是将检索要更新的存储的调用移动到update方法中。

    @Override
    public void updateStoreByStoreId(final long storeId) {
        getHibernateTemplate().execute(new HibernateCallback<Void>() {
            @Override
            public Void doInHibernate(Session session) throws HibernateException, SQLException {
                Store toBeUpdated =  (Store) session.createCriteria(Store.class)
                        .add(Restrictions.eq(Store.PROP_ID, storeId))
                        .uniqueResult();
    
                if (toBeUpdated != null){
                    // ..change values for certain fields
                    session.update(toBeUpdated );
                }
                return null;
            }
        });
    } 
    
        6
  •  0
  •   Claes Mogren BenLanc    14 年前

    如果你只想在代码的一部分上进行交易,你可以使用这样的东西:

    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    

    在课堂上:

    @Autowired private SessionFactory sessionFactory;
    

    稍后,围绕应该在同一事务中执行的代码:

    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    
    Stuff stuff = getStuff();
    manipulate(stuff);
    send(stuff);
    save(stuff);
    
    tx.commit();
    

    我在一些长时间运行的批处理作业中在循环中使用它。

        7
  •  0
  •   Piyush    8 年前

    我使用的是windows服务器IIS,只需将AppPool托管管道模式从集成更改为经典,就解决了我的问题。

    谢谢