@EntityListnersで注釈が付けられたエンティティークラスを利用するRESTful APIがあります。そして、EntityListner.javaには、@ PostPersistアノテーションが付けられたメソッドがあります。したがって、そのイベントが発生したときに、データベースに永続化されたエンティティに関するすべての情報を抽出したいと思います。しかし、それを実行しようとすると、Glassfishが例外を生成し、EntityListnerクラスのメソッドが期待どおりに実行されません。これがコードです
public class EntityListner {
private final static String QUEUE_NAME = "customer";
@PostUpdate
@PostPersist
public void notifyOther(Customer entity){
CustomerFacadeREST custFacade = new CustomerFacadeREST();
Integer customerId = entity.getCustomerId();
String custData = custFacade.find(customerId).toString();
String successMessage = "Entity added to server";
try{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
// channel.basicPublish("", QUEUE_NAME, null, successMessage .getBytes());
channel.basicPublish("", QUEUE_NAME, null, custData.getBytes());
channel.close();
connection.close();
}
catch(IOException ex){
}
finally{
}
}
}
custDataではなくコメント化されたsuccessMessageメッセージを送信すると、すべてが正常に機能します。
http://www.objectdb.com/java/jpa/persistence/eventは、エンティティのライフサイクルメソッドに関して次のように述べています。それがここの状況なのかどうか疑問に思っています。
エンティティライフサイクルイベント(まだ進行中)を発生させる元のデータベース操作との競合を回避するために、コールバックメソッドはEntityManagerまたはQueryメソッドを呼び出さないでください。
何か案は?
その段落で述べているように、標準はエンティティリスナーの内部からのエンティティマネージャーメソッドの呼び出しをサポートしていません。Heiko Ruppが彼の答えで言っているように、永続化されたエンティティから構築することを強くお勧めcustData
します。それが不可能な場合は、以下を検討してください。
public class EntityListener { private final static String QUEUE_NAME = "customer"; private ScheduledExecutorService getExecutorService(){ //どこかから非同期エグゼキューターサービスを取得 //多少の遅延で 通知をスケジュールするには// おそらく、ScheduledExecutorService インスタンスが必要になるでしょう。または、 通知する前にThread.sleep(...)//を試すこともできますが、これは醜い方法です。 } private void doNotifyOtherInNewTransaction(Customer entity){ //これをすべて正しく機能させるには、 // 新しいトランザクション内で// 通知を実行する必要があります。かもしれない //これを宣言的に実行する方が簡単です // // REQUIRES_NEWで 区切られたいくつかのメソッドを呼び出すことで// 試行{ //(トランザクションを開始) doNotifyOther(entity); //(トランザクションのコミット) } catch(例外ex){ //(ロールバックトランザクション) } } @PostUpdate @PostPersist public void notifyOther(final Customer entity){ ScheduledExecutorService executor = getExecutorService(); //これは「未加工」バージョンです //ほとんどの場合 、executor.schedule を呼び出し、遅延を指定する必要があります。 、古いトランザクションに //フラッシュしてコミットする時間を与えるために、// てexecutor.execute(新しいRunnableを(){ @Override ます。public void実行(){ doNotifyOtherInNewTransaction(エンティティ); } }); } //これは、元のコードとまったく同じです 。public void doNotifyOther(Customer entity){ CustomerFacadeREST custFacade = new CustomerFacadeREST(); 整数customerId = entity.getCustomerId(); 文字列custData = custFacade.find(customerId).toString(); String successMessage = "エンティティがサーバーに追加されました"; {を試す ConnectionFactoryファクトリ=新しいConnectionFactory(); factory.setHost( "localhost"); 接続connection = factory.newConnection(); チャネルチャネル= connection.createChannel(); channel.queueDeclare(QUEUE_NAME、false、false、false、null); channel.basicPublish( ""、QUEUE_NAME、null、custData.getBytes()); channel.close(); connection.close(); } catch(IOException ex){ } 最後に{ } } }
public class EntityListener { private final static String QUEUE_NAME = "customer"; private Transaction getTransaction(){ //どこかから現在のJTAトランザクション参照を取得 } private void doNotifyOtherInNewTransaction(Customer entity){ //これがすべて正しく機能するためには、 // 新しいトランザクション内で// 通知を実行する必要があります。 //宣言的に // REQUIRES_NEWで区切られたいくつかのメソッドを呼び出すことで// これを行う方が簡単かもしれません// {{ トランザクションを開始する) doNotifyOther(entity); //(トランザクションをコミット) }キャッチ(例外ex){ //(ロールバックトランザクション) } } @PostUpdate @PostPersist public void notifyOther(final Customer entity){ Transaction transaction = getTransaction(); transaction.registerSynchronization(新しい同期(){ @Override 公共ボイドbeforeCompletion(){} @Override 公共ボイドafterCompletion(INT状態){ (ステータス== Status.STATUS_COMMITTED){もし doNotifyOtherInNewTransaction(エンティティ); } } //これは元のコードとまったく同じ })。 } public void doNotifyOther(Customer entity){ CustomerFacadeREST custFacade = new CustomerFacadeREST(); 整数customerId = entity.getCustomerId(); 文字列custData = custFacade.find(customerId).toString(); String successMessage = "エンティティがサーバーに追加されました"; { ConnectionFactory factory = new ConnectionFactory();を試してください factory.setHost( "localhost"); 接続connection = factory.newConnection(); チャネルチャネル= connection.createChannel(); channel.queueDeclare(QUEUE_NAME、false、false、false、null); channel.basicPublish( ""、QUEUE_NAME、null、custData。 channel.close(); connection.close(); } catch(IOException ex){ } 最後に{ } } }
Springトランザクションを使用している場合、コードは非常によく似ており、クラス名がいくつか変更されています。
いくつかのポインタ:
非同期アクションをトリガーするためのScheduledExecutorService Javadoc
JTAとのトランザクション同期:トランザクションJavadocおよび同期Javadoc
同等のSpring:TransactionSynchronizationManager JavadocおよびTransactionSynchronization Javadoc。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加