반응형
목차
1. 회원 수를 증가시키기 위한 로직
@BeforeEach
void setUp() {
for (int i = 1; i <= 1000; i++) {
User mentee = new User(
"이멘티" + i, // 이름
"mentee" + i + "@naver.com", // 이메일
"이고수" + i, // 닉네임
"!@#1Qwer", // 비밀번호
"010-1111-" + String.format("%04d", i), // 번호
SocialType.LOCAL,
null,
UserRole.MENTEE,
UserGrade.SEED,
null
);
userRepository.save(mentee);
}
}
- 동시에 한 예약을 시도할 사용자들을 1000명 정도 생성함.
2. 예약 동시성 제어 테스트 코드
@Test
@DisplayName("AOP 를 활용한 분산락")
void concurrencyTestWithAop() {
LocalDateTime startAt = LocalDateTime.of(2025, 6, 15, 10, 0);
LocalDateTime endAt = LocalDateTime.of(2025, 6, 15, 10, 30);
AtomicInteger successCount = new AtomicInteger();
AtomicInteger failCount = new AtomicInteger();
ReservationRequestDto dto = new ReservationRequestDto(
1L, 5L, ReservationStatus.REQUESTED, startAt, endAt);
System.out.println("\n\n\n\n[concurrencyTestWithAOP]");
IntStream.range(1, 1000).parallel().forEach(i -> {
try{
reservationService.save((long) i, dto);
successCount.incrementAndGet();
}catch(BaseException e){
Log.error("실패: menteeId = " + i + ", 메시지 = " + e.getMessage());
failCount.incrementAndGet();
}
});
System.out.println("성공: " + successCount.get());
System.out.println("실패: " + failCount.get());
}
AtomicInteger successCount = new AtomicInteger();
AtomicInteger failCount = new AtomicInteger();
- 동시성(멀티 스레드) 환경에서 안전하게 값을 증가/ 감소시킬 수 있는 int 타입 변수.
IntStream.range(1, 1000).parallel().forEach(i -> {
try{
reservationService.save((long) i, dto);
successCount.incrementAndGet();
}catch(BaseException e){
Log.error("실패: menteeId = " + i + ", 메시지 = " + e.getMessage());
failCount.incrementAndGet();
}
});
- IntStream.range(1, 1000) → 1부터 999까지 정수 스트림을 생성함.
- parallel() → 해당 스트림을 병렬(멀티스레드) 스트림으로 변경.
3. 최종 코드
더보기
package caffeine.nest_dev.domain.reservation.service;
import caffeine.nest_dev.common.config.WebSocketConfig;
import caffeine.nest_dev.common.exception.BaseException;
import caffeine.nest_dev.domain.reservation.dto.request.ReservationRequestDto;
import caffeine.nest_dev.domain.reservation.enums.ReservationStatus;
import caffeine.nest_dev.domain.reservation.repository.ReservationRepository;
import caffeine.nest_dev.domain.user.entity.User;
import caffeine.nest_dev.domain.user.enums.SocialType;
import caffeine.nest_dev.domain.user.enums.UserGrade;
import caffeine.nest_dev.domain.user.enums.UserRole;
import caffeine.nest_dev.domain.user.repository.UserRepository;
import com.esotericsoftware.minlog.Log;
import jakarta.validation.constraints.AssertTrue;
import java.time.LocalDateTime;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
@SpringBootTest
@ActiveProfiles("test")
@ImportAutoConfiguration(exclude = WebSocketConfig.class)
public class ReservationTest {
@Autowired
private ReservationService reservationService;
@Autowired
private UserRepository userRepository;
@Autowired
private ReservationRepository reservationRepository;
@BeforeEach
void setUp() {
for (int i = 1; i <= 1000; i++) {
User mentee = new User(
"이멘티" + i, // 이름
"mentee" + i + "@naver.com", // 이메일
"이고수" + i, // 닉네임
"!@#1Qwer", // 비밀번호
"010-1111-" + String.format("%04d", i), // 번호
SocialType.LOCAL,
null,
UserRole.MENTEE,
UserGrade.SEED,
null
);
userRepository.save(mentee);
}
}
@Test
@DisplayName("AOP 를 활용한 분산락")
void concurrencyTestWithAop() {
LocalDateTime startAt = LocalDateTime.of(2025, 6, 15, 10, 0);
LocalDateTime endAt = LocalDateTime.of(2025, 6, 15, 10, 30);
AtomicInteger successCount = new AtomicInteger();
AtomicInteger failCount = new AtomicInteger();
ReservationRequestDto dto = new ReservationRequestDto(
1L, 5L, ReservationStatus.REQUESTED, startAt, endAt);
System.out.println("\n\n\n\n[concurrencyTestWithAOP]");
IntStream.range(1, 1000).parallel().forEach(i -> {
try{
reservationService.save((long) i, dto);
successCount.incrementAndGet();
}catch(BaseException e){
Log.error("실패: menteeId = " + i + ", 메시지 = " + e.getMessage());
failCount.incrementAndGet();
}
});
System.out.println("성공: " + successCount.get());
System.out.println("실패: " + failCount.get());
}
}
반응형
'스파르타 내일배움캠프 > TIL(Today I learned)' 카테고리의 다른 글
Backend와 Frontend 연결 방법 (1) | 2025.06.19 |
---|---|
면접 질문 (1) | 2025.06.18 |
에러코드 출력 관련 트러블 슈팅 (1) | 2025.06.16 |
Redisson 분산락 vs Redis 원자 연산 기반 동시성 제어 (2) | 2025.06.12 |
fix: 민원 관련 코드 수정 (0) | 2025.06.11 |