2012-06-30 22 views
11

JPAを新しいスレッドで使用してデータベースにデータを保存する簡単なソリューションはありますか?別のスレッド(実行可能)からトランザクションメソッドを呼び出す

My SpringベースのWebアプリケーションを使用すると、スケジュールされたタスクを管理できます。実行時に、事前定義されたタスクの新しいインスタンスを作成して開始することができます。私は春のTaskSchedulerを使用しており、すべてがうまくいきます。

しかし、私は、データベースにすべての火力タスクのブール結果を保存する必要があります。これどうやってするの?

EDIT: 私は私の質問を一般化する必要があります。私は仕事から私の@Serviceクラスのメソッドを呼び出す必要があります。データベースに保存する前にタスクの結果を "処理"する必要があるためです。

EDIT 2: 私の問題のあるコードの簡易版はここです。スケジューラーからsaveTaskResult()を呼び出すと、メッセージは出力されますが、dbには何も保存されません。しかし、コントローラからsaveTaskResult()を呼び出すたびに、レコードはデータベースに正しく保存されます。

@Service 
public class DemoService { 

    @Autowired 
    private TaskResultDao taskResultDao; 

    @Autowired 
    private TaskScheduler scheduler; 

    public void scheduleNewTask() { 
     scheduler.scheduleWithFixedDelay(new Runnable() { 

      public void run() { 
       // do some action here 
       saveTaskResult(new TaskResult("result")); 
      } 

     }, 1000L); 
    } 

    @Transactional 
    public void saveTaskResult(TaskResult result) { 
     System.out.println("saving task result"); 
     taskResultDao.persist(result); 
    } 

} 
+0

問題はなんですか?あなたはスレッドを開始し、スレッドを開始していない場合と全く同じようにSpringサービスを呼び出しますが、すべてがOKである必要があります。 –

+0

ターゲットビジネスメソッドが@Transactionalであるという問題があります。 run()でこのメソッドを呼び出すと、データは保持されません。 (私は質問タイトルを更新しました) –

+0

トランザクションインターセプタは、メソッドを呼び出すスレッドがサーブレットコンテナによって作成されたスレッドか、あなたによって作成されたスレッドかどうかは気にしません。それは動作するはずです。いくつかのコードを見せてください。 –

答えて

14

あなたのコードの問題は、あなたがsaveTaskResult()を呼び出すときにトランザクションが開始されることを期待ということです。これは、SpringがAOPを使用してトランザクションを開始および停止するために発生しません。

Beanファクトリからトランザクション用Spring Beanのインスタンスを取得した場合、または依存性注入を使用した場合は、実際にBeanの周囲にプロキシがあります。このプロキシは、実際のメソッドを呼び出す前にトランザクションを開始し、メソッドが完了するとトランザクションをコミットまたはロールバックします。この場合

は、あなたがトランザクションのプロキシを経由せずに、Beanのローカルメソッドを呼び出します。別のSpring BeanにsaveTaskResult()メソッド(@Transactionalと注釈付き)を入れてください。この他のSpring BeanをDemoServiceに挿入し、DemoServiceから他のSpring Beanを呼び出すと、すべて正常に動作します。

+0

素晴らしいです。これはまさに私が知る必要があったものです。ありがとうたくさん –

+0

ありがとう、百万。このソリューションは、charmのようなCompletableFutureで動作します。 –

2

トランザクションはスレッドローカルストレージに保持されます。
他のメソッドで@Transactionalアノテーションを持つスレッドが実行されている場合。
デフォルトはREQUIREDに設定されており、(このスレッドのスレッドローカルストレージに開催されたトランザクションがないとして)これは、あなたが別のスレッドから@Transacitonalアノテーションを付けるメソッドを実行した場合、あなたは新しいトランザクションを持っていることを意味します。

関連する問題