Maison  >  Article  >  Java  >  Comment résoudre le problème de l'utilisation asynchrone de SpringBoot avec les transactions

Comment résoudre le problème de l'utilisation asynchrone de SpringBoot avec les transactions

WBOY
WBOYavant
2023-05-27 14:37:241238parcourir

Un scénario que j'ai rencontré récemment était qu'une méthode B marquée par l'annotation @Async était appelée dans une méthode A annotée avec @Transactional Parce que la transaction de la méthode A n'était pas validée lors de l'exécution de la méthode B, mais que la méthode B était en cours d'exécution. processus. Les données non soumises dans la méthode A ne peuvent pas être obtenues, donc à la fin, la méthode B s'exécute anormalement.

@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);
}

Comme le code ci-dessus, j'ai marqué l'annotation de transaction @Transactional sur la méthode de création de l'utilisateur, puis j'ai appelé la méthode de mise à jour update(). Cette méthode a été marquée avec l'annotation @Async. Bien que le code ne semble poser aucun problème, lorsque la méthode update() est effectivement exécutée, car elle est exécutée par d'autres threads, il est possible que la transaction correspondant à la méthode create() n'ait pas encore été soumise et que la méthode update( ) ne peut pas le lire. L'enregistrement utilisateur nouvellement inséré est obtenu, ce qui entraîne l'échec de la mise à jour.

Solution

Assurez-vous que la transaction est validée avant d'appeler la méthode asynchrone en ajustant la logique

La raison de ce problème est due à l'utilisation des annotations @Transactional et @Async ensemble, alors nous pouvons commencer par cette direction, d'abord nous pouvons confirmer Après avoir soumis la transaction de la méthode create(), puis exécutez la méthode de mise à jour asynchrone :

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);
}

La méthode asynchrone est appelée en dehors de la méthode de transaction, afin que la méthode asynchrone puisse lire les données de transaction soumises.

Nous pouvons utiliser TransactionTemplate pour remplacer l'annotation @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);
}

En utilisant TransactionTemplate pour subdiviser la granularité de la transaction, assurez-vous que la transaction a été validée avant d'appeler la méthode asynchrone.

Les solutions ci-dessus peuvent essentiellement résoudre le problème. Voici la solution proposée par Spring trouvée sur Internet :

@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);
}

En enregistrant la méthode asynchrone en tant qu'opération après la soumission de la transaction, Spring peut automatiquement nous aider une fois la transaction terminée. soumis. Effectuez l’opération correspondante.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer