1

私はhibernate3.2.7(3.2.5でも同じ問題)をSpring 3.0.1で使用しており、すべてweblogic10.3とOracle10gデータベースにデプロイされています。私はJTAトランザクション管理を使用しており、トランザクションは分散されています(実際には別のアプリケーションで開始および終了され、このコードはちょうどその中間にあります)。

hibernateで使用される構成は、persistence.xmlで宣言されており、次のとおりです。

<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.WeblogicTransactionManagerLookup"/>
<property name="hibernate.query.factory_class" value="org.hibernate.hql.classic.ClassicQueryTranslatorFactory"/>
<property name="hibernate.current_session_context_class" value="jta"/>
<property name="hibernate.connection.release_mode" value="auto"/>

トランザクションマネージャーに関するSpring構成は次のとおりです。

<!-- Instructs Spring to perfrom declarative transaction managemenet on annotated classes -->
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>

<!-- Data about transact manager and session factory -->
<bean id="txManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager">
  <property name="transactionManagerName" value="javax.transaction.TransactionManager"/> 
  <property name="defaultTimeout" value="${app.transaction.timeOut}"/>
</bean>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <!-- persistence unit is missing jta data source so that application server is not 
      creating EntitiyManagerFactory, spring will create its own LocalContainerEntityManagerFactoryBean overriding data source-->
  <property name="dataSource" ref="myDataSource"/>
  <!-- specific properties like jpa provider and jpa provider properties are in persistance unit -->
  <property name="persistenceUnitName" value="my.persistence.unit"/>
</bean>


<!-- define data source in application server -->
<jee:jndi-lookup id="myDataSource" jndi-name="${db.jndiName}"/>

私は次のような更新メソッドを持つ一般的なCrudDaoを使用しています:

public void update(Object entity) {
    //entityManager injected by @PersistenceContext
    entityManager.merge(entity);
    entityManager.flush();
}

public Object getById(Object id, Class entityClass) throws PersistenceException{
    return (Object)entityManager.find(entityClass, id);
}

更新:getByIdメソッドを追加しました。

期待どおりに機能しないコードは次のようになります。

MyObject myObj = getMyObjectThroughSomeOneToManyRelation(idOne, idOther);
// till now was null
myObj.setSomeDateAttr(someDate);
genericDao.update(myObj); 

MyObject myObjFromDB = genericDao.getById(myObj.getId(), MyObject.class);

その結果、myObj.getSomeDateAttr()を出力すると、someDateの値が返されますが、myObjFromDB.getSomeDateAttr()を出力すると、nullが残ります。

更新方法を次のように変更してみました。

org.hibernate.Session s = (org.hibernate.Session) entityManager.getDelegate();
s.evict(entity);
s.update(entity);
s.flush();

そして、それはまだ機能しません。

hibernateのshow_sqlフラグをオンにすると、フラッシュを実行したり、同じIDのオブジェクトをエンティティマネージャーに照会したりしても、更新が発生しません。選択はすべて表示されます。更新:トランザクションの最後に更新が実際に呼び出され、すべてがデータベースに書き込まれます。ですから、私の問題はトランザクション中の「ちょうど」です。

この問題は、春と休止状態のトランザクションマネージャーの構成に関連している可能性があります。

私はすでに1日半を失ってしまったので、誰かが私を助けてくれることを願っています。

4

1 に答える 1

2

休止状態のマージ動作を詳しく調べる必要があります。ドキュメントによると

  • 現在セッションに関連付けられている同じ識別子を持つ永続インスタンスがある場合、指定されたオブジェクトの状態を永続インスタンスにコピーします
  • 現在セッションに関連付けられている永続インスタンスがない場合は、データベースからロードするか、新しい永続インスタンスを作成してください
  • 永続的なインスタンスが返されます
  • 指定されたインスタンスはセッションに関連付けられず、切り離されたままになります

ログのSQLクエリに関するあなたのステートメントによると、 MyObject myObj = getMyObjectThroughSomeOneToManyRelation(idOne, idOther); のようになります。永続オブジェクトを返しますが、それを変更して(ダーティになって)マージメソッドを呼び出すと、新しい状態がセッションの現在の永続オブジェクトにコピーされます。3 番目のポイント マージが永続オブジェクトを返す場合、これは実際には新しい管理可能な永続オブジェクトであり、後続の操作で使用する必要があります。

find メソッドを呼び出すと、hibernate はセッション内の永続オブジェクトを返しますが、管理可能な永続オブジェクトではありません。そのため、find によって返されるオブジェクトの変更が見つからないのです。

問題を解決するには、更新メソッドの返品タイプを変更してください

public Object update(Object entity) { 
    //entityManager injected by @PersistenceContext 
    return  entityManager.merge(entity); 
}

サービスでは、以下のように使用する必要があります

MyObject myObj = getMyObjectThroughSomeOneToManyRelation(idOne, idOther); 
// till now was null 
myObj.setSomeDateAttr(someDate); 
//You can use myObj as well instead myNewObj
MyObject myNewObj= genericDao.update(myObj);  
 //No need to call get
//MyObject myObjFromDB = genericDao.getById(myObj.getId(), MyObject.class); 
System.out.println("Updated value:"+myNewObj.getSomeDateAttr());

こちらのアーティクルもご覧ください。

于 2012-07-04T17:21:30.920 に答える