본문 바로가기
Sparta 내일배움캠프 Java 5기/[13주차] Spring 심화 Team Project ✓ 2024. 7. 15.

(24.07.15) Card 생성의 동시성 제어

Card 생성의 동시성 제어

  • Column과 Card(할일)에 관해서는 Position이라는 위치에 해당하는 값을 필드로 가지고 있기 때문에 동시에 DB에 접근해서 저장/삭제/수정을 할 경우에 대해서 위치가 겹쳐져서 데이터가 입력이 될 수 있으므로 이 부분에 동시성 제어를 적용하기로 결정
    • 물론 Redis 자체가 싱글 쓰레드이므로 RedisTemplate을 사용해도 문제는 없으나 실제로 적용하는 연습과 그 과정을 선택하기 위해 선택

RedissonConfig

@Configuration
public class RedissonConfig {

  ...

    public static final Long WAIT_TIME = 30L;

    public static final Long LEASE_TIME = 10L;

    @Bean
    public RedissonClient redissonClient() {

 ...

        config.useSingleServer()
                .setAddress(REDISSON_PREFIX + redisHost + ":" + redisPort);

        return Redisson.create(config);

    }

}
 
  • Redis에서 Login 부분에 이미 RedisTemplate을 사용하고 있었기 때문에 따로 분리하여 RedissonClient를 생성하여 Bean을 등록
  • 대기 시간과, Lock을 보유할 수 있는 시간을 상수로 지정해서 관리할 수 있도록 설정

Card  동시성 제어

private final RedissonClient redissonClient;

private static final String LOCK_KEY = "cardLock"
...

public CardResponseDto createCard(Long columnId, CardRequestDto requestDto) {

        RLock lock = redissonClient.getFairLock(LOCK_KEY);

        try {
            boolean isLocked = lock.tryLock(RedissonConfig.WAIT_TIME, RedissonConfig.LEASE_TIME, TimeUnit.SECONDS);
            if (isLocked) {
                try {
                
                   ...
                   
                    cardRepository.save(card);

                    return new CardResponseDto(card);
                } finally {
                    lock.unlock();
                }
            } else {
                throw new BadRequestException("다시 시도해 주세요.(Lock 얻기 실패)");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new BadRequestException("다시 시도해 주세요.(작업 실패)");
        }

    }
  • 주입받은 RedissonClient를 통해서 Lock을 가지고 있는지를 확인을 한 뒤(isLock) 가지고 있을 경우, save 로직을 진행이 되고, 없을 경우엔 대기시간에 따라 대기를 할 수 있도록 함