DataBase๋ ๋ฐ์ดํฐ๋ฅผ ์์์ ์ผ๋ก ์ ์ฅํ๊ณ ์๋ ์์คํ ์ด๋ค. ์ด๋ฐ ์์คํ ์ ๊ฐ์ ์์(๋ฐ์ดํฐ)์ ๋ํด์ ๋์์ ์ ๊ทผํ๋ ๊ฒฝ์ฐ๊ฐ ์๊ธธ ์ ๋ฐ์ ์๋ค. ์ด๋ด ๊ฒฝ์ฐ ๋ฐ์ดํฐ๊ฐ ์ค์ผ ๋ ์ ์๋๋ฐ ๊ทธ๋ ๊ฒ ๋์ง ์๋๋ก ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ๊ณผ ๋ฌด๊ฒฐ์ฑ์ ์ ์งํด์ผํ ํ์๊ฐ ์๋ค.
์๋ฅผ ๋ค์ด ์๊ฐ์ ์ฒญ ์์คํ ์์ 1๋ช ๋ง์ด ์ ์์ผ๋ก ๋จ๊ฒ๋์๋ค. ์ฌ๊ธฐ์ 2์ฌ๋์ด ๊ฑฐ์ ๋์์ ๋ฒํผ์ ๋๋ ๋ค. ์ฑ๊ณต์ 1๋ช ๋ง ๋์ผํ๋ค. ์ด๋ฐ ์ํฉ์์ DBMS(DataBase Management System)๊ฐ ์ฌ์ฉํ๋ ๊ณตํต์ ์ธ ๋ฐฉ๋ฒ์ด Lock์ด๋ผ๋ ๊ฒ๋ค.
1. Lock ์ด๋?
Lock์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋์์ฑ๊ณผ ๋ฐ์ดํฐ ์ผ๊ด์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ ๋ฉ์ปค๋์ฆ
ํน์ ํธ๋์ญ์ ์ฒ๋ฆฌ์ ์์ฐจ์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํ ๋ฐฉ๋ฒ
์ฌ๋ฌ ์ปค๋ฅ์ ์ด ํ๋์ Data์ ๋ํด ์ ๊ทผํ๋ ค๊ณ ํ ๋ ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ด ๋ณด์ฅ๋์ง ๋ชป ํ๋ ๋ฌธ์ ๊ฐ ์๋ค.
์ด๋ ํ๋์ ์ปค๋ฅ์ A๊ฐ Data์ ์ ๊ทผํ๋ฉด์ Lock์ ๊ฑธ์ด๋ฒ๋ฆฌ๋ฉด ๋ค๋ฅธ ์ปค๋ฅ์ (B,C,D)๋ Data์ ์ ๊ทผํ ์ ์๊ฒ ๋๋ค.
์ด๋ ๊ฒ ์๋ฌผ์ ๋ฅผ ๊ฑธ๊ณ ํธ๋ ํ์๋ฅผ Lock์ด๋ผ๊ณ ํ๋ค.
2. Lock๊ณผ Transaction ?
Lock๊ณผ Transaction์ ๊ฐ์ ์ญํ ์ ํ๋๊ฑธ๊น??
Lock์ ๋์์ ๋ฐ์ํ๋ ์์ ์์ฒญ์ ๋ํ ๋ฐ์ดํฐ ์ผ๊ด์ฑ์ ์งํค๊ธฐ ์ํ ๋ฉ์ปค๋์ฆ ์ค ํ๋์ด๋ค.
ํธ๋์ญ์ ์ ์ฌ๋ฌ ํธ๋์ญ์ ์ ๋ํด ๊ฐ ํธ๋์ญ์ ์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ์ง์ ๋ํ ์ ๋ต์ด๋ค.
์ ๋ฆฌํ๋ฉด ํธ๋์ญ์ ๋ค์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ์ง์ ๋ํ ์ ๋ต ์ค ๊ตฌํ ๋ฐฉ๋ฒ ์ค ํ๋๊ฐ Lock์ธ ๊ฒ์ด๋ค.
์ฆ, ํธ๋์ญ์ ์ ๊ฒฉ๋ฆฌ์์ค์ ๊ตฌํํ ๋ฐฉ๋ฒ ์ค ํ๋๊ฐ Lock์ด๋ค.
์ด ๋์ ๊ด๊ณ๋ ์ด์ฒ๋ผ ๋ํ๋ผ ์ ์๋ค.
3. Lock ์ ๋ต
- ๋๊ด์ Lock
ํธ๋์ญ์ ์ด ์ ์ด์ ์ถฉ๋์ด ๋ฐ์ํ์ง ์๋๋ค ๋ผ๊ณ ๊ฐ์ ํ๊ณ ์ฌ์ฉํ๋ ์ ๋ต
๋ด๊ฐ ๋จผ์ ์ด ๊ฐ์ ์์ ํ๋ค๊ณ ๋ช ์ํ์ฌ ๋ค๋ฅธ ์ฌ๋์ด ๋์ผํ ์กฐ๊ฑด์ผ๋ก ๊ฐ์ ์์ ํ ์ ์๊ฒ ํ๋ ๊ฒ์ด๋ค. ๊ทธ๋ฐ๋ฐ ์ ๋ณด๋ฉด ์ด ํน์ง์ DB์์ ์ ๊ณตํด์ฃผ๋ ํน์ง์ ์ด์ฉํ๋ ๊ฒ์ด ์๋ Application Level์์ ์ก์์ฃผ๋ Lock์ด๋ค.
- ๋น๊ด์ Lock
ํธ๋์ญ์ ์ด ๋งค๋ฒ ์ถฉ๋์ด ๋ฐ์ํ๋ค ๋ผ๊ณ ๊ฐ์ ํ๊ณ ์ฌ์ฉํ๋ ์ ๋ต
๋น๊ด์ ๋ฝ์ด๋ ํธ๋์ญ์ ์ด ์์๋ ๋ Shared Lock ๋๋ Exclusive Lock์ ๊ฑธ๊ณ ์์ํ๋ ๋ฐฉ๋ฒ์ด๋ค.
Shared Lock์ ๊ฑธ๊ฒ ๋๋ฉด write๋ฅผ ํ๊ธฐ์ํด์๋ Exclucive Lock์ ์ป์ด์ผํ๋๋ฐ Shared Lock์ด ๋ค๋ฅธ ํธ๋์ญ์ ์ ์ํด์ ๊ฑธ๋ ค ์์ผ๋ฉด ํด๋น Lock์ ์ป์ง ๋ชปํด์ ์ ๋ฐ์ดํธ๋ฅผ ํ ์ ์๋ค. ์์ ์ ํ๊ธฐ ์ํด์๋ ํด๋น ํธ๋์ญ์ ์ ์ ์ธํ ๋ชจ๋ ํธ๋์ญ์ ์ด ์ข ๋ฃ(commit) ๋์ด์ผํ๋ค.
์์ ๋์๋๋ฅผ ๋ณด๋ฉด์ ๋น๊ด์ ๋ฝ์ ๋ํด์ ์ ๋๋ก ์ดํดํด๋ณด์.
- Transaction_1 ์์ table์ Id 2๋ฒ์ ์ฝ์ ( name = Karol )
- Transaction_2 ์์ table์ Id 2๋ฒ์ ์ฝ์ ( name = Karol )
- Transaction_2 ์์ table์ Id 2๋ฒ์ name์ Karol2๋ก ๋ณ๊ฒฝ ์์ฒญ ( name = Karol )
- ํ์ง๋ง Transaction 1์์ ์ด๋ฏธ shared Lock์ ์ก๊ณ ์๊ธฐ ๋๋ฌธ์ Blocking
- Transaction_1 ์์ ํธ๋์ญ์ ํด์ (commit)
- Blocking ๋์ด์์๋ Transaction_2์ update ์์ฒญ ์ ์ ์ฒ๋ฆฌ
4. JPA์์์ ๋๊ด์ & ๋น๊ด์ Lock
๊ฐ์ ) ์ฟ ํฐ์ด 5์ฅ์ด ์๊ณ , 20๋ช ์ ์ฌ์ฉ์๊ฐ ๋์์ ์ฟ ํฐ์ ๋ฐ๊ธ๋ฐ์ ๋๋ฅผ ๊ฐ์
ํ ์คํธ๋ฅผ ์ํด Coupon ์ํฐํฐ์ Service ๋ก์ง์ ์์ฑํด์ฃผ์๋ค.
- Coupon
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class Coupon {
@Id
@GeneratedValue
@Column(name = "coupon_id")
private Long id;
private int count;
@Builder
public Coupon(int count) {
this.count = count;
}
public void issue() {
if (count <= 0) {
throw new IllegalArgumentException("์๋ ๋ถ์กฑ");
}
count -= 1;
}
}
DB์ ๋ค์๊ณผ ๊ฐ์ด ๋ฐ์ดํฐ๊ฐ ๋ค์ด๊ฐ์๋ค.
- case1: Lock์ ๊ฑธ์ง ์์์ ๋
@Test
@DisplayName("๋์์ ์ฟ ํฐ์ ๋ฐ๊ธํ ๊ฒฝ์ฐ - Lock ์ ์ฉ x")
void test_not_lock() throws InterruptedException {
final int executeNumber = 20;
ExecutorService executorService = Executors.newFixedThreadPool(10);
// ์ค๋ ๋์ ์คํ์ด ๋๋ ๋๊น์ง ๋๊ธฐ
CountDownLatch countDownLatch = new CountDownLatch(executeNumber);
AtomicInteger successCount = new AtomicInteger();
AtomicInteger failCount = new AtomicInteger();
for (int i = 0; i < executeNumber; i++) {
executorService.execute(() -> {
try {
couponService.issueCoupon(1);
successCount.getAndIncrement();
System.out.println("์ฟ ํฐ ๋ฐ๊ธ");
} catch (Exception e) {
failCount.getAndIncrement();
System.out.println(e.getMessage());
}
countDownLatch.countDown();
});
}
countDownLatch.await();
System.out.println("๋ฐ๊ธ๋ ์ฟ ํฐ์ ๊ฐ์ = " + successCount.get());
System.out.println("์คํจํ ํ์ = " + failCount.get());
assertEquals(failCount.get() + successCount.get(), executeNumber);
}
์ ์ฝ๋์ ๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ์ด ๋ํ๋๋ค.
DB์ ๋ถ๋ช ์ฟ ํฐ์ด 5๊ฐ ๋ฐ์ ์์ง๋ง ๋ฐ๊ธ๋ ์ฟ ํฐ์ ๊ฐ์๊ฐ 20๊ฐ๋ก ๋ํ๋๋ค. ์ด๋ฐ ๋ฌธ์ ๋ ๋งค์ฐ ํฌ๋ฆฌํฐ์ปฌํ ๋ฌธ์ ์ด๋ค.
์ด ๋ฌธ์ ๋ฅผ ๋จผ์ ๋๊ด์ Lock์ ์ฌ์ฉํด์ ํด๊ฒฐํด๋ณด์.
- case2: ๋๊ด์ Lock์ ๊ฑธ์์ ๋
Integer version ๋ถ๋ถ์ ์ ์ธํ๊ณค ์์์ ์์ฑํ entity์ ๋์ผํ๋ค.
version์ ์ํฐํฐ์ ์ ๊ทผํด์ ์ด๋ ํ ๊ฐ์ด ๋ณ๊ฒฝ๋ ๋ ์ด version์ด ๊ฐ์ด ์ฌ๋ผ๊ฐ๋ค.
์ฆ, ํ์ฌ ๋ฒ์ ์ด ๋ง๋์ง ์๋์ง ์๋ณํ๊ธฐ ์ํ ์ซ์์ด๋ค.
๋ฐ๋ผ์ update ์ฟผ๋ฆฌ๊ฐ ๋๊ฐ ๋ version์ ํ์ธํ๋ ์กฐ๊ฑด๋ฌธ์ด ํจ๊ป ๋๊ฐ๋ค.
์๊น ์์ฑํ Test ์ฝ๋๋ฅผ ๋๋ฆฌ๋ฉด ๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ์ด ๋์จ๋ค.
์ด๋ฒ์ ์ 3์ฅ์ธ ๊ฒ์ผ๊น? ์ฌ์ง์ด 5์ฅ๋ ์๋๋ค. ๊ทธ ์ด์ ๋ ๋๊ด์ Lock์ ์ต์ด์ ์์ฒญ๋ง commitํ๊ธฐ ๋๋ฌธ์ด๋ค. ์์ธํ๊ฒ ์ดํด๋ณด์.
๋ค์๊ณผ ๊ฐ์ด ํธ๋์ญ์ 4๊ฐ๊ฐ ๋์์ count์ ๊ฐ์ ๋ฐ๊พธ๋ ค๊ณ ํ ๋, ์ด๋์ version์ 1์ด๋ค.
ํธ๋์ญ์ A๊ฐ update๋ฌธ์ ์ํํ ๋ version์ ํ์ธํ๊ณ ํ์ฌ์ version๊ณผ ๋์ผํ๊ธฐ ๋๋ฌธ์ version์ 2๋ก ์ ๋ฐ์ดํธ ์์ผ์ค๋ค. ๋๋จธ์ง ํธ๋์ญ์ B,C,D๋ ๋ณธ์ธ๋ค์ version์ 1์ธ ๋ฐ๋ฉด ๋ฐ์ดํฐ์ version์ 2๊ฐ ๋๊ธฐ ๋๋ฌธ์ ์คํจํ๊ฒ ๋๋ ๊ฒ์ด๋ค.
์์ ๊ฐ์ ๋งค์ปค๋์ฆ์ผ๋ก ๋์ํ๊ธฐ ๋๋ฌธ์ ๋งค๋ฒ ๋ฐ๊ธ๋๋ ํฐ์ผ์ ๊ฐ์๊ฐ ๋ค๋ฅด๊ฒ ๋ํ๋ ์๋ ์๋ค.
ํ์ง๋ง ์ฌ๊ธฐ์ ํ์คํ ์ ์ ์ ๋ 5๊ฐ๋ฅผ ๋์ง๋ ์๋๋ค๋ ๊ฒ์ด๋ค.
- case3: ๋น๊ด์ Lock์ ๊ฑธ์์ ๋
JPA์์ repository์ ์กฐํ ํจ์์ Lock ์ด๋
ธํ
์ด์
์ ๊ฑธ์ด์ฃผ๋ฉด ๋น๊ด์ Lock์ ์ฌ์ฉํ ์ ์๋ค.
๋น๊ด์ Lock๊ฐ์ ๊ฒฝ์ฐ ์ ํํ 5๊ฐ๋ง ์ฟ ํฐ์ด ๋ฐ๊ธ๋๋ค. ๊ทธ ์ด์ ๋ ๋น๊ด์ Lock์ ํน์ง์ ์๋ค.
๋น๊ด์ Lock์ ๋ฐ์ดํฐ์ ์ ๊ทผํจ๊ณผ ๋์์ Lock์ ๊ฑธ์ด๋ฒ๋ฆฌ๊ธฐ ๋๋ฌธ์ ํ ๊ฐ์ ํธ๋์ญ์ ์ด ๋ฐ์ดํฐ์ ์ ๊ทผํ๋ ์๊ฐ ๋๋จธ์ง ํธ๋์ญ์ ์ ์ ๋ถ ๋๊ธฐํ๊ฒ ๋๋ค.
์ฟผ๋ฆฌ๋ฅผ ์ดํด๋ณด๋ฉด select for update ์ฟผ๋ฆฌ๊ฐ ๋๊ฐ๋๊ฑธ ๋ณผ ์ ์๋ค. ์ด ์ฟผ๋ฆฌ๊ฐ DB์ ์ ๊ทผํจ์ ๋ฐ๋ผ ์ฆ์ Lock์ ๊ฑฐ๋ ์ฟผ๋ฆฌ์ด๋ค.
๋น๊ด์ Lock์ ๋์ ๋งค์ปค๋์ฆ์ ๊ทธ๋ฆผ์ผ๋ก ์ดํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
ํธ๋์ญ์ A๊ฐ ๋ฐ์ดํฐ์ ์ ๊ทผํ์ ๋ ์ ๊ทผํ์๋ง์ Lock์ ๊ฑธ์ด๋ฒ๋ฆฌ๊ธฐ ๋๋ฌธ์ ์ด๋ค ํธ๋์ญ์ ๋ ๋์ผํ ๋ฐ์ดํฐ์ ์ ๊ทผํ ์ ์๋ค. ํธ๋์ญ์ A๊ฐ ๋ณผ์ผ์ ๋ค ๋ณด๊ณ Lock์ ํผ๋ค๋ฉด ๊ทธ๋ ๋๊ธฐํ๋ ํธ๋์ญ์ ์ด ์ ๊ทผํ ์ ์๋ค.
'DB ๐' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[replication] mysql Replication ์ผ๋ก DB ๋ถํ ๋ถ์ฐ ์ํค๊ธฐ (0) | 2024.04.11 |
---|---|
[Neo4j] Graph Database๋? RDBMS์ ๋น๊ต, neo4j ๋์ ์ด์ (1) | 2024.03.27 |
[Redis] redis์์ ๋ฐ์ดํฐ ์๊ตฌ ์ ์ฅํ๋ ๋ฐฉ๋ฒ (RDB / AOF) (0) | 2024.03.09 |
[Index] MySQL ์ฑ๋ฅ ์ต์ ํ (+์คํ ๊ณํ) (0) | 2024.02.19 |
[Index] ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ธ๋ฑ์ค ํํค์น๊ธฐ (0) | 2024.02.18 |