我正在尝试将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.LookupTableManager)中失败的代码:
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
答案 0 :(得分:5)
原来我根本没有交易。我在其他一个配置文件中使用了几乎相同的事务配置。
那边的切入点也被称为“经理”,所以我的顾问在这里引用了另一个文件中的切入点。
重命名切入点解决了我的问题。
答案 1 :(得分:3)
我的猜测是lookupTableDao.findById
调用是在一个会话中获取对象,但lookupTableDao.saveOrUpdate
是另一个会话 - 如何通过Spring获取Session
对象? / p>
Column
对象来自哪里 - 是已经在数据库中还是新的?
答案 2 :(得分:2)
问题出在Open Session In视图过滤器映射中。 它正在getSession上创建一个会话 还有其他的保存。
您只能将singleSession更改为false 默认是真的
答案 3 :(得分:2)
显然使用合并可能会解决问题
myInstance = (myInstanceClass) Session.merge(myInstance);
答案 4 :(得分:2)
我的以下代码遇到了同样的问题: 我想更新某个实体商店。我正在从这个方法中检索它:
@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方法的第一个会话没有关闭,我试图用其他会话更新商店。对我来说,解决方案是在更新方法中移动要检索商店的调用。
@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;
}
});
}
答案 5 :(得分:0)
如果您只希望对代码的一部分进行交易,则可以使用以下内容:
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();
我在一些长时间运行的批处理作业中使用它。
答案 6 :(得分:0)
我使用的是Windows服务器IIS,只是将AppPool Managed Pipeline模式从Integrated更改为Classic解决了我的问题。
由于