5

私は機械と部品のドメインクラスを持っています

私のサービスクラスでは、トランザクションを開始しようとしています。そのトランザクション内で、新しいトランザクションを作成し、内部トランザクションから出たときにコミットしたいと考えています。

Machine.withTransaction { // transaction 1
    // some code to add Parts

    // some code to remove Parts
    Machine.withNewTrasaction { // transaction 2
       // some code to remove Parts.
    } // end of transaction 2

// some code to update couple of columns in machine table.
}// end of transaction 1

それが出てきたら、マシンに関係なくパーツをコミットしたいのですが、 grailstransaction 2はエラーをスローしています。transaction 2transaction 1"Illegal attempt to associate a collection with two open sessions"transaction 2transaction 1

4

2 に答える 2

1

@Transactionalサービス クラス内のアノテーションを使用して、トランザクションを明示的に処理してみることができます。

ノート:-

  • @Transactionalサービス メソッドにアノテーションを追加すると、デフォルトではサービス クラスはトランザクションと見なされなくなります。
  • 機能を 2 つのメソッドに分割したためproxied、サービス クラスのインスタンスを使用して 2 番目のメソッドを呼び出す必要があります。そうしないと、2 番目のメソッドの新しいトランザクションを作成できません。したがって、applicationContext方法1で以下を使用します。
  • もう必要ないwithTransactionか、withNewTransactionブロックする必要はありません。

サービス クラスは次のようになります。

class MachineService{
   @Transactional
   def someMethodToAddParts(){
       ......
       grailsApplication.mainContext.machineService.someMethodToRemoveParts()
       ......
   }

   @Transactional(propagation = TransactionDefinition.PROPAGATION_REQUIRES_NEW)
   def someMethodToRemoveParts(){
     .......
   }
}
于 2013-07-09T21:15:31.023 に答える
0

少し異なる問題に遭遇しました。おそらく誰かを助けることができ、上記の問題を解決できるかもしれません。

上記の問題は、エンティティを新しいトランザクションにマージし、問題の原因となっているコレクションで .merge() メソッドを使用することで回避できると思います。

まず、上記のコードは次のようになると思います (説明のためにコメントを追加しました)。

Machine.withTransaction { // transaction 1
    // some code to add Parts

    yourEntity.addToParts(...)

    // some code to remove Parts
    Machine.withNewTrasaction { // transaction 2
       // some code to remove Parts.

       yourEntity.removeFromParts(...)


    } // end of transaction 2 -> the session is flushed, and the transaction is committed
      // during the flush, hibernate detect that "parts" collection is already attached
      // to another session, in another transaction then throw "Illegal 
      // attempt to associate a collection with two open sessions"

// some code to update couple of columns in machine table.
}

解決策は、コレクションを新しいトランザクションにマージすることです。これにより、次のような結果が得られます。

Machine.withTransaction { // transaction 1
    // some code to add Parts

    yourEntity.addToParts(...)

    // some code to remove Parts
    Machine.withNewTrasaction { // transaction 2
       // some code to remove Parts.

       yourEntity.removeFromParts(...)
       // Merging the collection to the session
       yourEntity.merge() // I haven't tried but maybe you need ensure 
                          // there is a merge cascade on "parts" collection

    } // end of transaction 2 -> the session is flushed, and the transaction is committed

// some code to update couple of columns in machine table.
}

私の場合、新しいトランザクションのマージで、「同じ識別子の値を持つ別のオブジェクトが既にセッションに関連付けられていました: [yourPackage.YourEntity]」というエラー メッセージを解決しました (YourEntity について話すときは、次のことも読むことができます)。あなたのドメインクラス)

于 2016-11-22T17:35:43.057 に答える