コレクションを2つの開いているセッションに関連付ける不正な試み
-
03-07-2019 - |
質問
別の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は、HibernateDaoSupportを拡張する単純なDAOクラスを指します。
エラーは次のとおりです:
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、私は受け取っている基本的なメッセージを理解しています。しかし、私が理解していないのは、2番目のセッションを取得する場所です....誰でもこれを手伝ってくれますか?
Hibernate 3.2.6.ga、Spring 2.5.5およびTomcat 6.0を使用しています
解決
取引がなかったことが判明。私は、他の構成ファイルの1つでほぼ同じトランザクション構成を使用しました。
そこのポイントカットは「マネージャー」とも呼ばれたため、ここでの私のアドバイザーは他のファイルのポイントカットを参照していました。
ポイントカットの名前を変更することで問題が解決しました。
他のヒント
lookupTableDao.findById
呼び出しは1つのセッションでオブジェクトを取得していますが、 lookupTableDao.saveOrUpdate
は別のセッションです-< code> Session オブジェクト、Spring経由
Column
オブジェクトはどこから来たのですか-それはすでにDB上にあるのですか、それとも新しいですか?
問題は、Open Session In Viewフィルターマッピングにありました。 getSessionでセッションを作成していました その他の保存。
singleSessionのみをfalseとして変更できます デフォルトはtrue
どうやらマージを使用すると問題が解決する可能性が高い
myInstance = (myInstanceClass) Session.merge(myInstance);
次のコードでも同じ問題が発生しました。 特定のエンティティストアを更新したかった。このメソッドから取得していました:
@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;
}
});
}
コードの一部でのみトランザクションが必要な場合は、次のようなものを使用できます。
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();
これは、長時間実行されるバッチジョブのループ内で使用します。
WindowsサーバーIISを使用していて、AppPool Managed PipelineモードをIntegratedからClassicに変更するだけで問題が解決しました。
ありがとう