2017-11-06 6 views
0

JEE CDIアプリケーションのビジネス層にサービスがあり、集中的な作業を実行する必要があります。これは別のスレッドで生成する必要があります。@ CDIを使用したサービススレッドのトランザクションEntityManager

public MyService { 
    public void doTask(MyDataKey myDataKey) { 
     MyThread myThread = new MyThread(myDataKey); 
     myThread.run(); 
    } 
} 

public MyThread : extends Thread { 
    MyDataKey myDataKey; 
    ... 
    public MyThread(MyDataKey inMyDataKey) { 
     this.myDataKey = inMyDataKey; 
    } 
    public void run() { 
     ... 
     myWorkerService.doWork(this.myDataKey); 
    } 
} 

public MyWorkerService { 
    @PersistenceContext(unitName = "default") EntityManager em; 
    ... 
    @Transactional 
    public void doWork(MyDataKey myDataKey) { 
     MyData myData = em.find(myDataKey.getId()); 
     myData.setStatus("Changed"); 
     ... (Set values for other properties) 
     MyDataChild myDataChild = new MyDataChild("Some Value"); 
     em.persist(myDataChild); 
     myData.addChild(myDataChild); 
     // According to documentation, flush should update myData 
     // and em.merge(myData) is not needed. 
    } 
    // When doWork() is exited, the transaction should commit the changes 
    // to MyData upon EM flush. 
} 

MyDataに関連する新しい要素を保持し、MyData属性を更新するには、EntityManagerを使用できる必要があります。奇妙なことに、em.persist(myDataChild)は機能し、新しいデータ要素は保存されますが、その参照とmyData属性への変更は保持されません。

私が遭遇している問題は、CDIを使用してMyThreadクラスのrun()オペレーションの範囲内でEntityManagerへのアクセスを取得するためにWorkerServiceを注入する方法です。

MyServiceでMyWorkerServiceを作成してスレッドに渡すと、EMフラッシュは明らかに機能しないため、@Transactionalメソッドが終了してMyThread.run()が終了してもMyDataのプロパティの変更は保持されません。完了しました。例えば

public MyService { 
    @Inject MyWorkerService myWorkerService; 
    ... 
    public void doTask(MyDataKey myDataKey) { 
     MyThread myThread = new MyThread(myWorkerService, myDataKey); 
     myThread.run(); 
    } 
} 


public MyThread : extends Thread { 
    MyWorkerService myWorkerService; 
    MyDataKey myDataKey; 
    ... 
    public MyThread(MyWorkerService inMyWorkerService, MyDataKey inMyDataKey) { 
     this.myWorkerService = inMyWorkerService; 
     this.myDataKey = inMyDataKey; 
    } 
    public void run() { 
     ... 
     myWorkerService.doWork(this.myDataKey); 
    } 
} 

上記のコードは、実際のコード

の簡略化した表現であり、これで発生するように見える問題が(MyWorkerServiceは、スレッド実行の外側に注入されるためであります)コンテキストで実行され、EntityManagerは親サービスコンテキストで同様に作成されますが、run()コンテキスト内で実行される@Transactionalワーカー操作内でEntityManagerが使用され、MyDataへの変更がDBに伝播されず、 MyDataインスタンスによって保持されません。

次は私が答えを求めている質問です:上記のように

1))(スレッド内で使用する労働者のサービスおよびEntityManagerを設定するための実行可能な方法MyThreadにMyWorkerServiceの通過しています.run()?すなわち、それぞれのCDI注入を保証する。

2)@Transactional doWork()操作内のMyDataインスタンスに対する変更が保持されたり保存されたりしないのはなぜですか?

3)スレッドの安全性を保証するthread.run()操作のコンテキスト内でEntityManagerを取得する方が良いでしょうか?

4)スレッドセーフであり、thread.run()の呼び出し内でEntityManagerと@Transactionalの正しい使い方を採用するために、どのコードを変更する必要がありますか?

答えて

0

Java EEはスレッドを作成するのをやめてしまいます。 Java EEは管理対象オブジェクトに関するもので、なので、スレッドなどのオブジェクトを作成して管理しないでください。

幸運にも、このようなタスクを最初に実行する必要はありません。あなたは、仕事をし、注射がまだ機能する管理された状況にあるためのいくつかの選択肢があります。

幸運を祈る!あなたが選択したものと理由を投稿してください。

+0

私の状況では、JMSと非同期のソリューションは本当に適切ではありません。私はManagedExecutorServiceで3番目のオプションを実装しようとしました。 WorkerServiceのインジェクションを取得し、TaskクラスをManagedExecutorService.submit()内で実行し、ManagedExecutorService.submit()内のWorkerServiceでワーカー・メソッドを呼び出すことができました。しかし、@ Transactionalアノテーションはtask.run()コンテキスト内ではもはや動作しないように見えます。トランザクションは、delegate WorkerService内で宣言され、run()内では直接宣言されません。 – Chris

+0

参照した記事は、タスク内でUserTransactionを適用します。 @TransactionalとCMTがManagedExecutorService.submit()のコンテキスト内でサポートされていないかどうか知っていますか? – Chris

関連する問題