新しいスレッドで JPA を使用してデータをデータベースに保存する簡単な解決策はありますか?
私の Spring ベースの Web アプリケーションでは、スケジュールされたタスクをユーザーが管理できます。実行時に、定義済みタスクの新しいインスタンスを作成して開始できます。私は Spring の TaskScheduler を使用しており、すべて正常に動作しています。
しかし、実行されたすべてのタスクのブール結果をデータベースに保存する必要があります。どうすればいいでしょうか?
編集: 質問を一般化する必要があります。タスクから @Service クラスのメソッドを呼び出す必要があります。タスクの結果は、データベースに保存する前に「処理」する必要があるためです。
編集 2: 問題のあるコードの簡略版はここにあります。saveTaskResult() がスケジューラから呼び出されると、メッセージは出力されますが、データベースには何も保存されません。ただし、コントローラから 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);
}
}
ベストアンサー1
コードの問題は、 を呼び出すとトランザクションが開始されることを期待していることですsaveTaskResult()
。Spring はトランザクションの開始と停止に AOP を使用するため、これは起こりません。
トランザクション Spring Bean のインスタンスを Bean ファクトリから、または依存性注入を通じて取得する場合、取得されるのは実際には Bean のプロキシです。このプロキシは、実際のメソッドを呼び出す前にトランザクションを開始し、メソッドが完了するとトランザクションをコミットまたはロールバックします。
この場合、トランザクション プロキシを経由せずに、Bean のローカル メソッドを呼び出します。メソッドsaveTaskResult()
( でアノテーションが付けられている@Transactional
) を別の Spring Bean に配置します。この別の Spring Bean を DemoService に挿入し、DemoService から別の Spring Bean を呼び出すと、すべて正常に動作します。