>  기사  >  Java  >  트랜잭션과 함께 SpringBoot를 비동기적으로 사용하는 문제를 해결하는 방법

트랜잭션과 함께 SpringBoot를 비동기적으로 사용하는 문제를 해결하는 방법

WBOY
WBOY앞으로
2023-05-27 14:37:241245검색

최근에 접한 시나리오는 @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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제