Java 非法尝试将一个集合与两个打开的会话相关联
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/221079/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Illegal attempt to associate a collection with two open sessions
提问by Jaap Coomans
I'm trying to add a pojo to a collection in another pojo. I'm sure I'm making a really stupid mistake somewhere along the lines but I can't figure out how to solve it.
我正在尝试将一个 pojo 添加到另一个 pojo 的集合中。我确定我在某处犯了一个非常愚蠢的错误,但我不知道如何解决它。
I have a pojo LookupTable which contains a list of Columns:
我有一个包含列列表的 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...
}
In my hibernate configuration I have:
在我的休眠配置中,我有:
<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>
In my Spring config file I have:
在我的 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>
And finally the code where it all fails within my manager class (com.foo.LookupTableManager):
最后是我的管理器类(com.foo.LookupTableManager)中所有失败的代码:
public void addColumnToTable(Column column, long tableId) {
LookupTable lookupTable = this.lookupTableDao.findById(tableId);
lookupTable.addColumn(column);
this.lookupTableDao.saveOrUpdate(lookupTable);
}
The variable lookupTableDao here refers to a simple DAO class which extends HibernateDaoSupport.
这里的变量 lookupTableDao 指的是一个简单的 DAO 类,它扩展了 HibernateDaoSupport。
The error I get is:
我得到的错误是:
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 ...
OK, I understand the basic message I'm getting. But what I don't understand is where I get the second session.... Can anyone help me with this?
好的,我明白我收到的基本信息。但我不明白的是我在哪里参加第二次会议......谁能帮我解决这个问题?
I'm using Hibernate 3.2.6.ga, Spring 2.5.5 and Tomcat 6.0
我正在使用 Hibernate 3.2.6.ga、Spring 2.5.5 和 Tomcat 6.0
采纳答案by Jaap Coomans
Turns out I didn't have a transaction at all. I used almost the same transaction configuration in one of my other config files.
结果我根本没有交易。我在其他配置文件之一中使用了几乎相同的事务配置。
The pointcut over there was also called "managers", so my advisor here was referencing the pointcut in the other file.
那边的切入点也被称为“管理器”,所以我的顾问在这里引用了另一个文件中的切入点。
Renaming the pointcut solved my problem.
重命名切入点解决了我的问题。
回答by Chris Kimpton
My guess is that the lookupTableDao.findById
call is getting your object in one session, but the lookupTableDao.saveOrUpdate
is a different one - how do you get the Session
object, via Spring?
我的猜测是lookupTableDao.findById
调用是在一个会话中获取您的对象,但这lookupTableDao.saveOrUpdate
是另一回事 - 您如何Session
通过 Spring获取对象?
Where is the Column
object coming from - is that already on the DB or new?
Column
对象来自哪里- 它已经在数据库中还是新的?
回答by Umar
The problem was with the Open Session In view filter mapping. It was creating a session on getSession And other on save.
问题在于 Open Session In 视图过滤器映射。它在 getSession 上创建了一个会话,并在 save 上创建了一个会话。
You can change only singleSession as false default its true
您只能将 singleSession 更改为 false 默认为 true
回答by Mark Bakker
Apparently using merge will probably fix the problem
显然使用合并可能会解决这个问题
myInstance = (myInstanceClass) Session.merge(myInstance);
回答by Claes Mogren
If you only want a transaction over a part of your code you can use something like this:
如果您只想对部分代码进行交易,则可以使用以下内容:
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
and in the class:
在课堂上:
@Autowired private SessionFactory sessionFactory;
Later, around the code that should do things in the same transaction:
后来,围绕应该在同一个事务中做事情的代码:
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Stuff stuff = getStuff();
manipulate(stuff);
send(stuff);
save(stuff);
tx.commit();
I use this inside a loop in some long-running batch jobs.
我在一些长时间运行的批处理作业的循环中使用它。
回答by Raul Rene
I had the same problem with my following code: I wanted to update a certain entity Store. I was retrieving it from this method:
我的以下代码遇到了同样的问题:我想更新某个实体商店。我从这个方法中检索它:
@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();
}
});
}
Then, I was updating the store in the following method:
然后,我使用以下方法更新商店:
@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;
}
});
}
It turns out I got the "Illegal attempt ..." error because the first session from the get method was not closing, and I was trying to update with the other session the store. The solution for me was to move the call for retrieving the store to be updated in the update method.
事实证明,我收到了“非法尝试...”错误,因为 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;
}
});
}
回答by Piyush
I was using windows server IIS and just changing the AppPool Managed Pipeline mode from Integrated to Classic solved my issue.
我正在使用 Windows 服务器 IIS,只是将 AppPool 托管管道模式从集成更改为经典解决了我的问题。
Thanks
谢谢