ホームページ  >  記事  >  Java  >  SpringBoot をトランザクションで非同期に使用する問題を解決する方法

SpringBoot をトランザクションで非同期に使用する問題を解決する方法

WBOY
WBOY転載
2023-05-27 14:37:241198ブラウズ

最近発生したシナリオは、@Async アノテーションでマークされたメソッド B が、@Transactional アノテーションが付けられたメソッド A で呼び出されたというものでした。メソッド B の実行時にメソッド A のトランザクションがコミットされていなかったため、メソッド B はコミットされませんでした。実行過程でメソッドAの未送信データが取得できず、最終的にメソッドBが異常実行されてしまいます。

@Transactional
public void create(User user){
  // 如果用户已存在,则先删除
  delete(user.id);
  // 创建用户
  int userId = insert(user);
  //  更新用户信息
  update(userId);
}
@Async
public void update(Integer userId){
  Icon icon = getUserIcon(userId);
  // 更新用户图片
  updateUserPohot(userId,icon);
}

上記のコードのように、ユーザーを作成するメソッドに @Transactional トランザクション アノテーションをマークし、その中で update() 更新メソッドを呼び出しました。このメソッドには @Async アノテーションが付けられました。コード上は問題なさそうに見えますが、実際に update() メソッドを実行すると、他のスレッドで実行されるため、create() メソッドに対応するトランザクションがまだ投入されていない可能性があり、update( ) メソッドはそれを読み取れません。新しく挿入されたユーザー レコードが取得されるため、更新が失敗します。

解決策

非同期メソッドを呼び出す前にトランザクションが確実にコミットされるようにロジックを調整してください

この問題の原因は、@Transactional と @Async の使用にあります。アノテーションを一緒に作成したら、この方向から開始できます。まず、create() メソッドのトランザクションが送信されたことを確認し、次に非同期更新メソッドを実行します:

public void create(User user){
  int userId = doCreate(user);
  //  更新用户信息
  update(userId);
}
@Transactional
public void doCreate(User user){
    // 如果用户已存在,则先删除
  delete(user.id);
  // 创建用户
  return insert(user);
}
@Async
public void update(Integer userId){
  Icon icon = getUserIcon(userId);
  // 更新用户图片
  updateUserPohot(userId,icon);
}

非同期メソッドは外部で呼び出されます。トランザクションメソッドを使用して、非同期メソッドでコミットされたトランザクションデータを読み取ることができます。

TransactionTemplate を使用して @Transactional アノテーションを置き換えることができます

@Autowired
TransactionTemplate transactionTemplate;
public void create(User user){
  int userId = transactionTemplate.execute(status->{
    // 如果用户已存在,则先删除
    delete(user.id);
    // 创建用户
    return insert(user);
  });
  //  更新用户信息
  update(userId);
}
@Async
public void update(Integer userId){
  Icon icon = getUserIcon(userId);
  // 更新用户图片
  updateUserPohot(userId,icon);
}

TransactionTemplate を使用してトランザクションの粒度を細分化し、非同期メソッドを呼び出す前にトランザクションがコミットされていることを確認します。

上記の解決策で基本的に問題は解決できますが、インターネット上で見つかった Spring の解決策は次のとおりです:

@Transactional
public void create(User user){
  // 如果用户已存在,则先删除
  delete(user.id);
  // 创建用户
  int userId = insert(user);
  TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
    @Override
    public void afterCommit() {
      //  更新用户信息
      update(userId);
    }
  });
}
@Async
public void update(Integer userId){
  Icon icon = getUserIcon(userId);
  // 更新用户图片
  updateUserPohot(userId,icon);
}

トランザクション送信後に非同期メソッドをオペレーションとして登録することで、Spring はこれは、トランザクションの送信後に対応する操作を実行するのに自動的に役立ちます。

以上がSpringBoot をトランザクションで非同期に使用する問題を解決する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。