โญ์๊ตฌ์ฌํญ
์ฝ๋์ค์ฟผ๋์ Airbnb ํ๋ก์ ํธ ์ค
๊ฐ์ ์์์ ์ฌ๋ A ์ ์ฌ๋ B ๊ฐ ๋์์ ์์ฝ์ ์์ฒญํ ๊ฒฝ์ฐ, ํ ๊ฑด์ ์์ฝ๋ง ์ฑ๊ณตํด์ผ ํฉ๋๋ค.
(๊ฐ์ ์์๋ฅผ ์ฌ๋ A์ ์ฌ๋ B๊ฐ ๋์์ ์ฌ์ฉํ๋ฉด ์๋๋๊น!)
โญ๊ณ ๋ฏผ
๊ทธ๋์, ๋์์ ์์ฝ ์์ฒญ์ ๋ง๊ธฐ ์ํด
- ๋น๊ด์ ๋ฝ
- ๋๊ด์ ๋ฝ
- DB์ ์ ๋ํฌ ์ ์ฝ์กฐ๊ฑด
์ ๊ณ ๋ฏผํ๊ฒ ๋์์ต๋๋ค.
โญํด๊ฒฐ ๊ณผ์
์์ฝ์ด ์ ์ฅ๋๋ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
@Transactional
public BookingResponse create(BookingSaveRequest request) {
// ์์ฒญํ ์์ฝ์ด ๊ธฐ์กด ์์ฝ์ ์ผ์ ๊ณผ ์ค๋ณต๋๋์ง ํ์ธํ๋ ๋ก์ง
Long bookedStayCount = bookingRepository.countBookedStay(request.getStayId(), request.getCheckIn(), request.getCheckOut());
if (bookedStayCount > 0) {
throw new IllegalArgumentException("์์ฝ ๋ถ๊ฐ์
๋๋ค.");
}
// ์์ฝ์ ์์ฒญํ ์ฌ๋์ด ํ์์ธ์ง ํ์ธ
Member member = memberRepository.findById(request.getMemberId())
.orElseThrow();
// ์์๊ฐ ์์ฝ ์ธ์์ ์์ฉํ ์ ์๊ณ , ์ฌ์ฉ ๊ฐ๋ฅํ์ง ํ์ธ
Stay findStay = stayRepository.findById(request.getStayId())
.orElseThrow(() -> new IllegalArgumentException("์์ ๋ชป์ฐพ์์"));
findStay.validateExceedGuest(request.getGuestCount());
findStay.validateOpenStatus();
Booking entity = Booking.builder()
...(์ค๋ต)
.build();
// ์์ฝ์ DB์ ์ ์ฅ
try {
Booking saved = bookingRepository.save(entity);
return BookingResponse.of(saved);
} catch (PersistenceException error) {
์์ธ์ฒ๋ฆฌ
}
}
์ ์ฝ๋์์ DB์ ์ ๊ทผํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ก์ง์
1. Long bookedStayCount = bookingRepository.countBookedStay
2. Member member = memberRepository.findById
3. Stay findStay = stayRepository.findById
์ด๋ ๊ฒ ์ด 3๊ฐ์ง๊ฐ ์์ต๋๋ค.
๊ทธ๋ฌ๋, ์ด 3๊ฐ์ง ๊ฒฝ์ฐ ๋ค DB์์ ๋ฐ์ดํฐ๋ฅผ ์กฐํ๋ง ํ ๋ฟ, update ๋ฅผ ํ๊ฑฐ๋ delete ๋ฅผ ํ์ง ์์ต๋๋ค.
๋๊ด์ ๋ฝ๊ณผ ๋น๊ด์ ๋ฝ์ ์ธ์ ์ฌ์ฉํ ์ง๋ฅผ ๊ณต๋ถํ๊ธฐ ๋๋ฌธ์,
ํ ํธ๋์ญ์
์์ DB์ ์ ๊ทผํด์ ์กฐํ๋ง ํ๋ ์ ๊ฒฝ์ฐ์๋ ๋ฝ์ด ์ ํฉํ์ง ์๋ค๊ณ ํ๋จํ์ต๋๋ค.
๋ํ, bookingRepository.save(entity) ๋ DB์ INSERT INTO ์ฟผ๋ฆฌ๊ฐ ๋ ๋ผ๊ฐ ๋ฟ,
SELECT ์ฟผ๋ฆฌ๋ ์คํ๋์ง ์๊ธฐ ๋๋ฌธ์ ๋น๊ด์ ๋ฝ๊ณผ ๋๊ด์ ๋ฝ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ฌผ๋ก , ๊ฒฉ๋ฆฌ์์ค SERIALIZABLE ๋ก ์ค์ ํด์ ํธ๋์ญ์ ์ ์์ฐจ์ ์ผ๋ก ์คํ์ํฌ ์ ์์ง๋ง
์์ด๋น์ค๋น ์๋น์ค ํน์ฑ ์ ์ฃผ๋ก ์์ ์กฐํ์ ๋ง์ DB ์ปค๋ฅ์ ์ด ์ฌ์ฉ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์
ํธ๋์ญ์ ์ ์์ฐจ์ ์ผ๋ก ์คํํ์ฌ ๋์ ์ฒ๋ฆฌ๋์ ๋ฎ์ถ๋ ๊ฒ์ ์ ํฉํ์ง ์๋ค๊ณ ํ๋จํ์ต๋๋ค.
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ DB์ ์ ๋ํฌ ์ ์ฝ ์กฐ๊ฑด์ ์ฌ์ฉํ์ฌ, ๋์ ์์ฝ ์์ฒญ์ ๋ง๊ณ ์ ํ์์ต๋๋ค.
์ ๋ํฌ ์ ์ฝ ์กฐ๊ฑด์ ์์ฝ ์ํฐํฐ์ ์์ID, ์ฒดํฌ์ธ, ์ฒดํฌ์์๋ก ์ค์ ํ์ฌ
๊ฐ์ ๋ ์ง์ ๊ฐ์ ์์์ 2๊ฐ ์ด์์ ์์ฝ์ด ์๊ธฐ์ง ์๋๋ก ํ์์ต๋๋ค.
/* ์์ฝ ์ํฐํฐ */
@Table(name = "BOOKING",
uniqueConstraints = {
@UniqueConstraint(columnNames = {"STAY_ID", "CHECK_IN", "CHECK_OUT"})}
)
@Entity
public class Booking extends BaseTimeEntity {
์ด์ , ํ
์คํธ ์ฝ๋๋ฅผ ์ฌ์ฉํ์ฌ ๋์ ์์ฝ ์์ฒญ์ด ๋ง์์ง๋์ง ํ์ธํด๋ณด๊ฒ ์ต๋๋ค.
ํ
์คํธ๋ ์์ฝ Request ๋ฅผ ๋ง๋ค์ด์ ๋ฉํฐ ์ฐ๋ ๋ ํ๊ฒฝ์์ ๋์์ request ๋ฅผ ๋ณด๋์ ๋,
DB์ ๋ช ๊ฑด์ด ์ ์ฅ๋๋์ง ํ์ธํฉ๋๋ค.
@Test
void ๋์_์์ฝ_์์ฒญ์ด_์ค๋๋ผ๋_1๊ฑด๋ง_์์ฝ๋๋ค() throws InterruptedException {
// ์์ฝ ์์ฒญ ์์ฑ
LocalDateTime checkIn = LocalDateTime.of(LocalDate.of(2024, 11, 1), LocalTime.of(15, 0, 0));
LocalDateTime checkOut = LocalDateTime.of(LocalDate.of(2024, 11, 2), LocalTime.of(12, 0, 0));
// ๋ฉค๋ฒID ๊ฐ 1์ธ ์ฌ๋์ด ์์ID๊ฐ 1์ธ ๊ณณ์ ์์ฝ ์์ฒญ
BookingSaveRequest request = new BookingSaveRequest(1L, 1L, checkIn, checkOut, 2);
AtomicInteger successCount = new AtomicInteger();
AtomicInteger failCount = new AtomicInteger();
long originCount = bookingRepository.count();
int requestCount = 30;
ExecutorService executorService = Executors.newFixedThreadPool(requestCount);
CountDownLatch latch = new CountDownLatch(requestCount);
for (int i = 0; i < requestCount; i++) {
executorService.submit(() -> {
try {
bookingService.create(request);
successCount.incrementAndGet();
} catch (Exception e) {
failCount.incrementAndGet();
} finally {
latch.countDown();
}
});
}
latch.await();
System.out.println("successCount = " + successCount);
System.out.println("failCount = " + failCount);
long changeCount = bookingRepository.count();
Assertions.assertThat(originCount + 1).isEqualTo(changeCount);
}
ํ
์คํฌ ์ฝ๋์ ๋ํ ์ค๋ช
-> ๋งํฌ
ํ
์คํธ์ ๊ฒฐ๊ณผ๋ก, ์ฑ๊ณตํ ๊ฐ์๋ 1๊ฐ, ์คํจํ ๊ฐ์๋ 29๊ฐ๊ฐ ๋์ค๊ฒ ๋์๊ณ ,
์ ๋ํฌ ์ ์ฝ ์กฐ๊ฑด์ ์ํด DB์ ์ฝ์
๋์ง ๋ชปํ ํธ๋์ญ์
์ ๋ค์๊ณผ ๊ฐ์ด ์๋ฌ๊ฐ ๋ฐ์ํ๊ฒ ๋์์ต๋๋ค.
2024-07-01T12:34:40.659+09:00 ERROR 24864 --- [clone] [pool-2-thread-2] o.h.engine.jdbc.spi.SqlExceptionHelper : Duplicate entry '1-2024-11-01 15:00:00.000000-2024-11-02 12:00:00.000000' for key 'BOOKING.UKl92471cusp79py2jcwnxaph0e'
DB์ ์์ฝ ํ
์ด๋ธ์๋ ๋จ 1๊ฑด๋ง ์ ์ฅ๋จ์ ํ์ธํ ์ ์์์ต๋๋ค.
์ฐธ๊ณ ๋งํฌ
ํ ์ฝ๋ธ - ๋์ ์๋งค ์์คํ