Database/SQL

์ฃผ๋ฌธ ์‹œ ์žฌ๊ณ ์ˆ˜๋Ÿ‰์ด ๋งˆ์ด๋„ˆ์Šค๊ฐ€ ๋˜๋Š” ๋™์‹œ์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐํ•˜๊ธฐ

์ฑ”๐Ÿป 2024. 2. 9. 20:41

๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ฉฐ ๊ฒช์€ ๋ฌธ์ œ๋“ค

๐Ÿšฉย ๋“ค์–ด๊ฐ€๋ฉฐ


์‹ค๋ฌด์—์„œ๋Š” ์ •๋ง ๋‹ค์–‘ํ•˜๊ณ  ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ฌธ์ œ๋“ค์„ ํ•ด๊ฒฐํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์ „์— ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ• ์ง€ ๊ฐ€์ •์„ ํ•ด๋ณด๊ณ , ํ•ด๊ฒฐํ•ด๋ณด๋Š” ๊ฒฝํ—˜์ด ๊ต‰์žฅํžˆ ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

ํŒ€ ํ”„๋กœ์ ํŠธ๋กœ ๊ฐœ๋ฐœํ•œ ์‡ผํ•‘๋ชฐ ํ”„๋กœ์ ํŠธ์—์„œ ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์„๊นŒ๋ฅผ ๊ณ ๋ฏผํ•ด๋ณด์•˜๋Š”๋ฐ, ์–ผ๋งˆ ์ „์— ์ฝ์€ โ€œ๋ฐ์ดํ„ฐ ์ค‘์‹ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค๊ณ„โ€๋ผ๋Š” ์ฑ…์˜ 7์žฅ ํŠธ๋žœ์žญ์…˜์—์„œ ์ค‘์š”ํ•˜๊ฒŒ ๋‹ค๋ฃฌ ๋™์‹œ์„ฑ ๋ฌธ์ œ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ด๋ณด๊ฒŒ๋๋‹ค.

๐Ÿ‘€ย ๋ฌธ์ œ ์ƒํ™ฉ & ๋ฐœ์ƒ ์›์ธ


1. ๋ฌธ์ œ์ƒํ™ฉ

2๋ช…์˜ ์‚ฌ์šฉ์ž๊ฐ€ ์žฌ๊ณ ๊ฐ€ ํ•˜๋‚˜ ๋‚จ์€ ์ƒํ’ˆ์„ ๋™์‹œ์— ์ฃผ๋ฌธ์„ ์‹œ๋„ํ–ˆ์„ ๋•Œ, ์žฌ๊ณ ์ˆ˜๋Ÿ‰ ๊ฒ€์ฆ ๋กœ์ง์ด ์žˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์žฌ๊ณ ๊ฐ€ ๋งˆ์ด๋„ˆ์Šค๊ฐ€ ๋˜๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒ.

์žฌ๊ณ ์ˆ˜๋Ÿ‰ ๊ฒ€์ฆ ๋กœ์ง

2๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๋กœ ๋ฌธ์ œ ์ƒํ™ฉ์„ ๋ฐœ์ƒ์‹œ์ผœ๋ณด์ž.

@Test
public void orderQtyTest() throws Exception {
    // 1. ํ…Œ์ŠคํŠธํ•  ์ƒํ’ˆ์˜ ์žฌ๊ณ ์ˆ˜๋Ÿ‰์„ 1๋กœ ์„ค์ •ํ•œ๋‹ค.(opt_comb_no = 1, 2)
    int[] optCombArr = {1};
    int[] invQtyArr = {1};
    int updateInvQtyresult = setInvQty(optCombArr, invQtyArr);

    // ์žฌ๊ณ ์ˆ˜๋Ÿ‰ ๋ณ€๊ฒฝ์ด ์ž˜ ๋˜์—ˆ๋Š”์ง€ ์ฒดํฌ
    assertTrue(optCombArr.length == updateInvQtyresult);

    // 2. 2๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๋กœ ์ด 10๊ฐœ์˜ ์ฃผ๋ฌธ์„ ์‹œ๋„ํ•œ๋‹ค.
    int numberOfThreads = 2;
    int ordersPerThread = 5;

    ExecutorService executorService = Executors.newFixedThreadPool(numberOfThreads);

    for (int i = 0; i < numberOfThreads; i++) {
        executorService.execute(() -> {
            for (int j = 0; j < ordersPerThread; j++) {
                Order order = FOS_OrderServiceImplTest.getOrder();
                try {
                    // ์ฃผ๋ฌธ์„ ์ƒ์„ฑํ•œ๋‹ค.
                    service.order(order);
                } catch (Exception e) {
                    e.printStackTrace();
                    fail("์ฃผ๋ฌธ ์ƒ์„ฑ ์‹คํŒจ");
                }
            }
        });
    }

    // ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
    executorService.shutdown();
    while (!executorService.isTerminated()) {
        // ๋Œ€๊ธฐ
    }

    // 3. ์žฌ๊ณ ์ˆ˜๋Ÿ‰์ด ๊ธฐ๋Œ€ํ•œ๊ฐ’๋Œ€๋กœ 0์ธ์ง€ ์ฒดํฌ
    List<ProdOptDTO> prodOptDTOList = prodOptDAO.selectProductQty(optCombArr);
    int totalProdInvQty = prodOptDTOList.stream().mapToInt(ProdOptDTO::getInvQty).sum();

    assertEquals(0, totalProdInvQty);
}

์ดˆ๊ธฐ ์žฌ๊ณ ์ˆ˜๋Ÿ‰์€ 1๊ฐœ. 2๋ช…์˜ ์‚ฌ์šฉ์ž๊ฐ€ ๋™์‹œ์— ๊ฐ™์€ ์ƒํ’ˆ์„ ์ฃผ๋ฌธํ–ˆ์„ ๊ฒฝ์šฐ์— ์กฐ๊ธˆ ๋Šฆ๊ฒŒ ๋“ค์–ด์˜จ ์‚ฌ์šฉ์ž๋Š” ์žฌ๊ณ ์ˆ˜๋Ÿ‰ ๊ฒ€์ฆ ๋กœ์ง์— ๊ฑธ๋ ค ์ฃผ๋ฌธ์ด ์•ˆ ๋˜์—ˆ์–ด์•ผ ํ•˜๋‚˜ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ์žฌ๊ณ ์ˆ˜๋Ÿ‰์€ -1๊ฐœ๊ฐ€ ๋˜์—ˆ๊ณ  ์‹ค์ œ๋กœ ์ฃผ๋ฌธ์ด ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

2. ๋ฐœ์ƒ์›์ธ

MySQL์˜ ๊ธฐ๋ณธ Isolation Level์€ Repeatable Read๋‹ค. Tx์ด ์‹œ์ž‘๋œ ์ดํ›„ ๋ณ€๊ฒฝ์€ ๋ฌด์‹œ๋˜๋Š” ์™„ํ™”๋œ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์ด๋‹ค. ์ด๋ ‡๊ฒŒ Repeatable Read ๊ฒฉ๋ฆฌ์—์„œ๋Š” ํŠธ๋žœ์žญ์…˜์—์„œ์˜ ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ์„ ๋ณด์žฅํ•˜์ง€๋งŒ, ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ๋™์‹œ์— ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜๋ ค๊ณ  ํ•  ๊ฒฝ์šฐ์—๋Š” ์ด๋Ÿฐ ๋™์‹œ์„ฑ ๋ฌธ์ œ(๊ฐฑ์‹  ์†์‹ค, ์“ฐ๊ธฐ ์Šคํ, ํŒฌํ…€)๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค

์‚ฌ์ง„ ์ถœ์ฒ˜ - ์Šคํ”„๋ง์˜ ์ •์„

๋‚ด๊ฐ€ ๊ฒช์€ ์ƒํ™ฉ์„ ๊ทธ๋ฆผ์œผ๋กœ ๋‚˜ํƒ€๋‚ด์ž๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค. ์ด๋Ÿฐ Repeatable Read์˜ ํŠน์„ฑ๋•Œ๋ฌธ์— ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒƒ์ด๋‹ค.

<๋ฌธ์ œ ๋ฐœ์ƒ ๊ณผ์ •>

  1. ์ฃผ๋ฌธ ํŠธ๋žœ์žญ์…˜1 ์‹œ์ž‘ ๋ฐ ์Šค๋ƒ…์ƒท ์ƒ์„ฑ: ์žฌ๊ณ ์ˆ˜๋Ÿ‰ 1๊ฐœ
  1. ํŠธ๋žœ์žญ์…˜1 ์žฌ๊ณ ์ˆ˜๋Ÿ‰ ๊ฒ€์ฆ: ์žฌ๊ณ ์ˆ˜๋Ÿ‰์ด 1๊ฐœ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฒ€์ฆ ํ†ต๊ณผ
  1. ํŠธ๋ž™์žญ์…˜1์—์„œ ์žฌ๊ณ ์ˆ˜๋Ÿ‰์„ ๊ฐ์†Œ & ์ฃผ๋ฌธ ์ƒ์„ฑ: ์žฌ๊ณ ์ˆ˜๋Ÿ‰ 1๊ฐœ โ†’ 0๊ฐœ
  1. ์ฃผ๋ฌธ ํŠธ๋žœ์žญ์…˜2 ์‹œ์ž‘ ๋ฐ ์Šค๋ƒ…์ƒท ์ƒ์„ฑ: ํŠธ๋žœ์žญ์…˜2๊ฐ€ ์‹œ์ž‘๋œ ์‹œ์ ์—์„œ ์žฌ๊ณ ์ˆ˜๋Ÿ‰์€ 1๊ฐœ์ด๊ธฐ ๋•Œ๋ฌธ์— ์žฌ๊ณ ์ˆ˜๋Ÿ‰์ด 1๊ฐœ์ธ ์Šค๋ƒ…์ƒท์„ ์ƒ์„ฑ
  1. ํŠธ๋žœ์žญ์…˜1์—์„œ ์ƒ์„ฑํ•œ ๋ฐ์ดํ„ฐ ์ปค๋ฐ‹: DB์— ์˜๊ตฌ์ ์œผ๋กœ ๋ฐ˜์˜
  1. ํŠธ๋žœ์žญ์…˜2 ์žฌ๊ณ ์ˆ˜๋Ÿ‰ ๊ฒ€์ฆ: ํŠธ๋žœ์žญ์…˜1์—์„œ ๋ณ€๊ฒฝํ•œ ์žฌ๊ณ ์ˆ˜๋Ÿ‰ ๋ฐ์ดํ„ฐ๊ฐ€ ์ปค๋ฐ‹์ด ๋˜์—ˆ์ง€๋งŒ ๋‚ด ์Šค๋ƒ…์ƒท(์žฌ๊ณ ์ˆ˜๋Ÿ‰ 1๊ฐœ)์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์žฌ๊ณ ์ˆ˜๋Ÿ‰์„ ๊ฒ€์ฆํ•œ๋‹ค. ์ด๋กœ์ธํ•ด ์žฌ๊ณ ์ˆ˜๋Ÿ‰ ๊ฒ€์ฆ์— ํ†ต๊ณผํ•œ๋‹ค.
  1. ํŠธ๋ž™์žญ์…˜2์—์„œ ์žฌ๊ณ ์ˆ˜๋Ÿ‰์„ ๊ฐ์†Œ & ์ฃผ๋ฌธ ์ƒ์„ฑ: ์žฌ๊ณ ์ˆ˜๋Ÿ‰ 0๊ฐœ โ†’ -1๊ฐœ
  1. ํŠธ๋žœ์žญ์…˜2์—์„œ ์ƒ์„ฑํ•œ ๋ฐ์ดํ„ฐ ์ปค๋ฐ‹: ์žฌ๊ณ ์ˆ˜๋Ÿ‰์ด -1๊ฐœ์ธ์ฑ„๋กœ DB์— ์˜๊ตฌ์ ์œผ๋กœ ๋ฐ˜์˜

Repeatable Read๋Š” ์Šค๋ƒ…์ƒท ๊ฒฉ๋ฆฌ์ด๊ณ , MVCC๋กœ ๊ตฌํ˜„๋˜์–ด์žˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ผ๊ด€๋œ ๋ณด๊ธฐ(Read Consistency)๋ฅผ ์œ ์ง€ํ•˜๊ฒŒ ํ•ด์ค€๋‹ค. ์ƒ์„ธํ•œ ๋‚ด์šฉ์€ ์•„๋ž˜๋ฅผ ์ฐธ๊ณ .

MVCC(Multi-Version Concurrency Control)
1. MVCC์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š” ๋ฐฉ๋ฒ•1) Current๋””์Šคํฌ์—์„œ ์บ์‹œ๋กœ ์ ์žฌ๋œ ์›๋ณธ ๋ธ”๋ก์„ ํ˜„์žฌ ์ƒํƒœ ๊ทธ๋Œ€๋กœ ์ฝ๋Š” ๋ฐฉ์‹ 2) Consistent์ฟผ๋ฆฌ๊ฐ€ ์‹œ์ž‘๋œ ์ดํ›„์— ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์—์„œ ์˜ํ•ด ๋ณ€๊ฒฝ๋œ ๋ธ”๋ก์„ ๋งŒ๋‚˜๋ฉด ์›๋ณธ ๋ธ”๋ก์œผ๋กœ๋ถ€ํ„ฐ ๋ณต์‚ฌ๋ณธ(CR copy) ๋ธ”๋ก์„ ๋งŒ๋“ค๊ณ , ๊ฑฐ๊ธฐ์— Undo ๋ฐ์ดํ„ฐ๋ฅผ ์ ์šฉํ•จ์œผ๋กœ์จ ์ฟผ๋ฆฌ๊ฐ€ โ€˜์‹œ์ž‘๋œ ์‹œ์ โ€™์œผ๋กœ ๋˜๋Œ๋ ค์„œ ์ฝ๋Š” ๋ฐฉ์‹ 2. SCN(System Commit Number)Consistent ๋ชจ๋“œ๋ฅผ ์ดํ•ดํ•˜๋ ค๋ฉด SCN์„ ์•Œ์•„์•ผ ํ•œ๋‹ค. Consistent ๋ชจ๋“œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋‹ค๊ฐ€ ๋ธ”๋ก SCN > ์ฟผ๋ฆฌ SCN ? ๋ณธ์‚ฌ๋ณธ ๋ธ”๋ก ๋งŒ๋“ค๊ณ , Undo ๋ฐ์ดํ„ฐ๋ฅผ ์ ์šฉํ•œ๋‹ค.โ‡’ ์ฟผ๋ฆฌ๊ฐ€ ์‹œ์ž‘๋œ ์‹œ์ ์œผ๋กœ ๋˜๋Œ๋ ค์„œ Read Consistency๊ฐ€ ๊ฐ€๋Šฅํ•ด์ง„๋‹ค. SELECT : ํ•ญ์ƒ Consistent ๋ชจ๋“œ๋กœ..
https://beppp.tistory.com/26

๐Ÿ’ช๐Ÿปย ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•


1. Serializable ์ ์šฉ

  • ์žฅ์  : ๋ฐ์ดํ„ฐ ํ’ˆ์งˆโ†‘
  • ๋‹จ์  :
    • ๋ชจ๋“  ๊ฑธ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅโ†“
    • ๋ฐ๋“œ๋ฝ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค. โ†’ ํŠธ๋žœ์žญ์…˜์ด ๋กค๋ฐฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณ‘๋ ฌ์ฒ˜๋ฆฌ๊ฐ€ ๊ฑฐ์˜ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ๋ณด๋ฉด ๋จ

/**
 * ์ฃผ๋ฌธ์„ ์ƒ์„ฑํ•œ๋‹ค.
 *
 * @throws Exception ์ฃผ๋ฌธ ์ฒ˜๋ฆฌ ๋„์ค‘ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ
 * @author min
 * @since 2023/07/07
 */
@Override
@Transactional(rollbackFor = Exception.class, isolation = Isolation.SERIALIZABLE)
public void order(Order order) throws Exception {
    // 0-1. ์žฌ๊ณ ์ˆ˜๋Ÿ‰ ๊ฐ์†Œ
    decreaseProdQty(order.getOrdDtlList());

2. ๋‚™๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด(Optimistic Concurrency Control)

์ •์˜

๋งˆ์ง€๋ง‰์œผ๋กœ ์ฝ์€ ํ›„๋กœ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์„ ๋•Œ๋งŒ ๊ฐฑ์‹ ์„ ํ—ˆ์šฉํ•จ์„์จ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

์›๋ž˜๋Š” ๋จผ์ € ๊ฒ€์‚ฌ๋ฅผ ํ•˜๊ณ  ๋ณ€๊ฒฝ ์‹œ๋„๋ฅผ ํ•ด์•ผ ํ•˜๋Š”๋ฐ ์„ค๋งˆ ๋ณ€๊ฒฝ๋˜์–ด์žˆ๊ฒ ์–ด? ํ•˜๊ณ  ๋‚™๊ด€์ ์œผ๋กœ ์ ‘๊ทผํ•ด, ๋ฐ์ดํ„ฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์ „์— ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ฝํžŒ ํ›„ ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ. ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋ฉด ์ถฉ๋Œ์„ ๊ฐ์ง€ํ•ด ํŠธ๋žœ์žญ์…˜์„ ๋กค๋ฐฑํ•œ๋‹ค.

์žฅ์ ๊ณผ ๋‹จ์ 

  • ์žฅ์ : ์„ฑ๋Šฅ ์ธก๋ฉด์—์„œ ๋น„๊ด€์  ๋ฝ๋ณด๋‹ค ์ผ๋ฐ˜์ ์œผ๋กœ ์šฐ์ˆ˜ํ•œ ๊ฒƒ์œผ๋กœ ์•Œ๋ ค์ ธ ์žˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•  ๋•Œ ๋ฝ์„ ๊ฑธ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž๊ฐ€ ๋™์‹œ์— ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋‹จ์ :
    1. ์ž์› ๊ฒฝํ•ฉ์ด ๋นˆ๋ฒˆํ•˜๊ฒŒ ๋ฐœ์ƒํ•˜๋Š” ์ƒํ™ฉ์—์„œ ์‹คํŒจํ–ˆ์„ ๋•Œ์˜ ์ฒ˜๋ฆฌ ๋น„์šฉ์ด ๋†’๋‹ค. ํ˜„์žฌ ๊ฐ’์ด ์ด์ „์— ์ฝ์€ ๊ฐ’๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด read-modify-write ์ฃผ๊ธฐ๋ฅผ ์žฌ์‹œ๋„ํ•ด์•ผ ํ•œ๋‹ค.
    1. ๋™์ผํ•œ ์ƒํ’ˆ์— ์ฃผ๋ฌธ์ด ๋ชฐ๋ฆด ๊ฒฝ์šฐ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•ด ํŠธ๋žœ์žญ์…˜์ด ๋กค๋ฐฑ๋  ๊ฒƒ์ด๊ณ  ์žฌ์‹œ๋„ ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜๊ฒ ์ง€๋งŒ ๋ฌดํ•œ์œผ๋กœ ์žฌ์‹œ๋„ ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜๋Š” ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ •ํ•ด๋‘” ์žฌ์‹œ๋„ ํšŸ์ˆ˜๋ฅผ ๋„˜์–ด๊ฐ€๊ฒŒ๋˜๋ฉด ์ฃผ๋ฌธ์ด ์‹คํŒจํ•˜๊ฒŒ๋˜์–ด ๊ณ ๊ฐ์ด ๋ถˆํŽธํ•จ์„ ๊ฒช๊ฒŒ๋œ๋‹ค.

์ ์šฉ๋ฐฉ๋ฒ•

  1. ํ•ด๋‹น ์ปฌ๋Ÿผ๋งŒ ๋น„๊ต

    ์ฒ˜์Œ ์žฌ๊ณ ์ˆ˜๋Ÿ‰์„ ์กฐํšŒํ•ด์˜ค๊ณ  ๋งˆ์ง€๋ง‰์œผ๋กœ ์ฝ์€ ํ›„๋กœ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์„ ๋•Œ๋งŒ ๊ฐฑ์‹ ์„ ํ—ˆ์šฉํ•จ์„์จ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

    ์žฌ๊ณ ์ˆ˜๋Ÿ‰ ๊ฐ์†Œ ๋กœ์ง์— ์ฒ˜์Œ ์ฝ์–ด์™”์„ ๋‹น์‹œ์˜ ์žฌ๊ณ ์ˆ˜๋Ÿ‰์„ ์žฌ๊ณ ์ˆ˜๋Ÿ‰์„ ๊ฐ์†Œ์‹œํ‚ค๋Š” ์ฟผ๋ฆฌ์— param์œผ๋กœ ๋„˜๊ฒจ์ค˜์•ผ ํ•ด ์ถ”๊ฐ€ ์ฝ”๋“œ ์ˆ˜์ •์ด ํ•„์š”ํ•˜๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

    UPDATE prod_opt
    SET INV_QTY = INV_QTY - #{new_qty}
    WHERE OPT_COMB_NO = #{optCombNo}
    AND INV_QTY = #{old_qty} # ๋งˆ์ง€๋ง‰ ์ฝ์€ ์ดํ›„๋กœ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์„ ๋•Œ๋งŒ
  1. ๋ณ€๊ฒฝ์ผ์‹œ = ํƒ€์ž„์Šคํƒฌํ”„

    ๋ฐ์ดํ„ฐ์˜ ์ตœ์ข… ๋ณ€๊ฒฝ ์‹œ๊ฐ„์„ ํƒ€์ž„์Šคํƒฌํ”„๋กœ ๊ด€๋ฆฌํ•˜๊ณ , ์ด๋ฅผ ํ†ตํ•ด ๋ณ€๊ฒฝ ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

    1๋ฒˆ ๋ฐฉ๋ฒ•์€ ์ผ๋ฐ˜์ ์ธ ์ƒํ™ฉ์—์„œ ํ™•์žฅ์„ฑ์ด ์ข‹์ง€ ์•Š๋‹ค. ์žฌ๊ณ ์ˆ˜๋Ÿ‰์ด ๋“ค์–ด์žˆ๋Š” prod_opt ์ปฌ๋Ÿผ์—๋Š” ๋‹ค๋ฅธ ์ปฌ๋Ÿผ์ด ๊ฐ™์ด ๋ณ€๊ฒฝ๋  ์ผ์€ ์—†์–ด์„œ ๋‹ค๋ฅธ ์˜ˆ์‹œ๋ฅผ ๋“ค์–ด๋ณด์ž๋ฉด..


    ์šฐ์ˆ˜ ๊ณ ๊ฐ์„ ๋Œ€์ƒ์œผ๋กœ ์ ๋ฆฝํฌ์ธํŠธ๋ฅผ ์ œ๊ณตํ•˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ์‹ค์‹œํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ, ๊ณ ๊ฐ์˜ ์‹ค์ ์ •๋ณด๋ฅผ ์ฝ์–ด ์ ๋ฆฝ ํฌ์ธํŠธ๋ฅผ ๊ณ„์‚ฐํ•ด ๋ณ€๊ฒฝํ•œ๋‹ค. ์ ๋ฆฝ ํฌ์ธํŠธ๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋™์•ˆ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ๊ฐ™์€ ๊ณ ๊ฐ์˜ ์‹ค์ ์ •๋ณด๋ฅผ ๋ณ€๊ฒฝํ•œ๋‹ค๋ฉด ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค.

    ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋‚™๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด ๋ฐฉ๋ฒ•์„ ์ ์šฉํ•˜๊ณ  ๋ฒ„์ „ ์ปฌ๋Ÿผ์ด ์•„๋‹Œ ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•ด์•ผ ํ•˜๋Š” ์ปฌ๋Ÿผ์„ ์ผ์ผ์ด ์จ์ฃผ์—ˆ์„ ๊ฒฝ์šฐ์— ์ผ๋‹จ ๊ท€์ฐฎ๊ณ  ์ถ”ํ›„์— ์‹ค์ ์ •๋ณด๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค๋ฉด ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•˜๋Š” ๊ด€๋ฆฌ ํฌ์ธํŠธ๊ฐ€ ๋Š˜์–ด๋‚˜๊ณ  ๋ณด๊ธฐ์—๋„ ์ข‹์ง€ ์•Š๋‹ค.

    UPDATE ๊ณ ๊ฐ 
    SET ์ ๋ฆฝํฌ์ธํŠธ = #{์ ๋ฆฝํฌ์ธํŠธ}
    WHERE ๊ณ ๊ฐ๋ฒˆํ˜ธ = #{๊ณ ๊ฐ๋ฒˆํ˜ธ}
    AND ์ ๋ฆฝํฌ์ธํŠธ = #{old_์ ๋ฆฝํฌ์ธํŠธ}
    AND ๋ฐฉ๋ฌธํšŸ์ˆ˜ = #{old_๋ฐฉ๋ฌธํšŸ์ˆ˜}
    AND ์ตœ๊ทผ๋ฐฉ๋ฌธ์ผ์‹œ = #{old_์ตœ๊ทผ๋ฐฉ๋ฌธ์ผ์‹œ}
    AND ๊ตฌ๋งค์‹ค์  = #{old_๊ตฌ๋งค์‹ค์ }

    ๋ฒ„์ „ ์ปฌ๋Ÿผ์ด๋‚˜ ์ตœ์ข…๋ณ€๊ฒฝ์ผ์‹œ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ปฌ๋Ÿผ์ด ์žˆ๋‹ค๋ฉด ์กฐ๊ฑด์ ˆ์— ๋„ฃ์–ด ๊ฐ„๋‹จํžˆ ํ•ด๋‹น ๋ ˆ์ฝ”๋“œ์˜ ๊ฐฑ์‹ ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๋‹ค.

    UPDATE ๊ณ ๊ฐ 
    SET ์ ๋ฆฝํฌ์ธํŠธ = #{์ ๋ฆฝํฌ์ธํŠธ}
    WHERE ๊ณ ๊ฐ๋ฒˆํ˜ธ = #{๊ณ ๊ฐ๋ฒˆํ˜ธ}
    AND ๋ณ€๊ฒฝ์ผ์‹œ = #{๋ณ€๊ฒฝ์ผ์‹œ} # ์ตœ์ข… ๋ณ€๊ฒฝ์ผ์‹œ๊ฐ€ ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘ ์‹œ์ ์— ์ฝ์€ ๊ฐ’๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ๋น„๊ต

    ๋‚˜์˜ ๊ฒฝ์šฐ์—๋Š” ์ด๋ ‡๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

    UPDATE prod_opt
    SET INV_QTY = INV_QTY - #{qty}
      , UPD_DTTM = now()
    WHERE OPT_COMB_NO = #{optCombNo}
    AND UPD_DTTM = #{updDttm} -- ์ˆ˜์ •์ผ์‹œ

    ํ•˜์ง€๋งŒ ์ด ๋ฐฉ๋ฒ•์€ ๋‚˜์˜ ์ƒํ™ฉ์— ๋ฐ”๋กœ ์ ์šฉํ•˜๊ธฐ์—๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ๋‹ค.

    ์ตœ์ข… ๋ณ€๊ฒฝ ์‹œ๊ฐ„์„ ํ™œ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ฝํžŒ ์ดํ›„ ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํŒ๋‹จํ•˜๋Š” ๋ฐฉ์‹์€, ์‹œ๊ฐ„ ๋‹จ์œ„๊ฐ€ ๋ฐ€๋ฆฌ์ดˆ๊นŒ์ง€ ๊ณ ๋ ค๋˜์–ด์•ผ๋งŒ ์ •ํ™•ํ•œ ๋น„๊ต๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. UPD_DTTM ์ปฌ๋Ÿผ์˜ ๋ฐ์ดํ„ฐ ํƒ€์ž…์€ TIMESTAMP๋กœ, ์†Œ์ˆ˜์  ์ดํ•˜์˜ ์ดˆ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก ์ •๋ฐ€๋„๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค.

    ๋˜ํ•œ prod_opt์— ๋ณ€๊ฒฝ์ด ๋ฐœ์ƒํ•  ์‹œ ํ˜„์žฌ๋Š” now() ๋ฉ”์„œ๋“œ๋กœ ๋ณ€๊ฒฝ์ผ์‹œ๋ฅผ ๋„ฃ์–ด์ฃผ๊ณ  ์žˆ๋Š”๋ฐ now() ๋ฉ”์„œ๋“œ๋Š” ์‹œ๋ถ„โ€™์ดˆโ€™๊นŒ์ง€๋งŒ ๋‚˜ํƒ€๋‚ธ๋‹ค. ๋ฐ€๋ฆฌ์ดˆ๊นŒ์ง€ ํ‘œํ˜„ํ•˜๋ ค๋ฉด ์ •๋ฐ€๋„๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” CURRENT_TIMESTAMP๋ฅผ ์ด์šฉํ•ด์•ผ ํ•œ๋‹ค.

    ๋ณ€๊ฒฝ ํฌ์ธํŠธ๊ฐ€

    1. UPD_DTTM ์ปฌ๋Ÿผ์˜ ๋ฐ์ดํ„ฐ ํƒ€์ž… TIMESTAMP โ†’ TIMESTAMP(3) ๋ณ€๊ฒฝ
    1. ๋ณ€๊ฒฝ์ผ์‹œ๋ฅผ now() โ†’ CURRENT_TIMESTAMP(3) ๋ณ€๊ฒฝ

    ์ด๋ ‡๊ฒŒ 2๊ตฐ๋ฐ๋‚˜ ๋˜๊ณ , ์ถ”๊ฐ€ ์ฝ”๋“œ ์ˆ˜์ •์ด ๋งŽ์•„์ง€๊ณ  ๊ด€๋ฆฌ ํฌ์ธํŠธ๊ฐ€ ๋Š˜์–ด๋‚˜๊ฒŒ๋œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

    ๊ด€๋ จํ•ด์„œ๋Š” ์•„๋ž˜๋ฅผ ์ฐธ๊ณ 

    ์ ์šฉํ•˜๋ฉด์„œ ์‚ฝ์งˆ ๊ณผ์ •์ด ๊ถ๊ธˆํ•˜์‹  ๋ถ„๋“ค์€ ์•„๋ž˜ ๊ธ€ ์ฐธ๊ณ ,,

  1. ๋ฒ„์ „ ์ปฌ๋Ÿผ

    ํŠธ๋žœ์žญ์…˜์ด ์‹œ๊ฐ„๋œ ํ›„ ๋ฒ„์ „์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด ๋ฒ„์ „์ด ๊ฐ™์•„์•ผ update๋ฅผ ์ˆ˜ํ–‰, ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋ฉด update๋ฅผ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๊ณ  ํŠธ๋žœ์žญ์…˜์„ ๋กค๋ฐฑํ•˜๋Š” 2๋ฒˆ์ด๋ž‘ ๋น„์Šทํ•œ ๋ฐฉ๋ฒ•

    UPDATE prod_opt
    SET INV_QTY = INV_QTY - #{qty}
      , UPD_DTTM = now()
    WHERE OPT_COMB_NO = #{optCombNo}
    AND versione = #{version} 

    2์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์ด๋‹ค.

    ์ด ๋ฐฉ๋ฒ•๋„ 2๋ฒˆ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ prod_opt ํ…Œ์ด๋ธ”์— ๋ฒ„์ „ ์ปฌ๋Ÿผ์„ ์ถ”๊ฐ€ํ•ด์ค˜์•ผ ํ•˜๊ณ , ์žฌ๊ณ ์ˆ˜๋Ÿ‰์ด ๋ณ€๊ฒฝ๋˜๋Š” ๋ชจ๋“  ์ฟผ๋ฆฌ์— version๋„ ๊ฐ™์ด + ๋˜๋Š” ์ฟผ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•ด์ค˜์•ผ ํ•˜๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

  1. JPA์˜ @Version

    JPA๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๋‚™๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ @Version ์• ๋„ˆํ…Œ์ด์…˜์œผ๋กœ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ MyBatis๋งŒ์„ ์‚ฌ์šฉํ•˜๋Š” ๋‚ด ํ”„๋กœ์ ํŠธ์—๋Š” ๋‹น์žฅ ์ ์šฉ์ด ์–ด๋ ต๋‹ค.

  1. ์ˆ˜๋Ÿ‰ ๋น„๊ต

    ๊ตฌ๋งคํ•˜๋ ค๋Š” ์ˆ˜๋Ÿ‰์ด ํ˜„์žฌ ์ˆ˜๋Ÿ‰๋ณด๋‹ค ๋งŽ์ด ๋‚จ์•„์žˆ๋Š”์ง€๋ฅผ ์ฒดํฌํ•˜์—ฌ ๋‚™๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

    ์ถ”๊ฐ€ ์ฝ”๋“œ ์—†์ด๋„ ๊ฐ€์žฅ ์‰ฝ๊ณ  ๊น”๋”ํ•˜๊ฒŒ ๊ตฌํ˜„ ๊ฐ€๋Šฅ.

    <update id="decreaseProdQty" parameterType="Map">
        UPDATE prod_opt
        SET INV_QTY = INV_QTY - #{qty}
          , UPD_DTTM = now()
        WHERE OPT_COMB_NO = #{optCombNo}
        AND INV_QTY >= #{qty}
    </update>

๋‚˜๋Š” 5๋ฒˆ โ€˜์ˆ˜๋Ÿ‰ ๋น„๊ตโ€™๋ฅผ ์„ ํƒํ•ด ๋‚™๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค. ๋‹ค๋ฅธ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•  ํ•„์š” ์—†์ด ๊ฐ€์žฅ ๊น”๋”ํ•˜๊ณ  ์‰ฝ๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์žฌ์‹œ๋„ ์ฒ˜๋ฆฌ

๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ๋‚™๊ด€๋ฝ์œผ๋กœ ํ•ด๊ฒฐํ–ˆ๋‹ค๋ฉด ์žฌ์‹œ๋„ ๋กœ์ง์„ ๋ฐ˜๋“œ์‹œ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ๊ฒฝํ•ฉ ๋ฐœ์ƒ ์‹œ ์˜ˆ์™ธ๋ฅผ ๊ฐ•์ œ๋กœ ๋ฐœ์ƒ์‹œ์ผœ ํŠธ๋žœ์žญ์…˜์„ ๋กค๋ฐฑํ•˜๊ณ  ์žฌ์‹œ๋„ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š์œผ๋ฉด, ์‚ฌ์šฉ์ž๋Š” ๋‹ค์‹œ ์ฃผ๋ฌธ์„ ์‹œ๋„ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž๊ฐ€ ๊ฒช๊ฒŒ๋˜๋Š” ๋ถˆํŽธํ•จ์ด ํฌ๋‹ค.

์ถฉ๋Œ์ด ๊ฐ์ง€๋˜์–ด ๋กค๋ฐฑ๋˜์—ˆ์„ ๊ฒฝ์šฐ์— ์žฌ์‹œ๋„ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด @Retryable ์• ๋„ˆํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ–ˆ๋‹ค. ์žฌ์‹œ๋„ ํšŸ์ˆ˜๋Š” 3ํšŒ๋กœ ์ œํ•œํ•˜์˜€๋‹ค.

์Šคํ”„๋ง์—์„œ ์žฌ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ @Retryable ์‚ฌ์šฉํ•˜๊ธฐ
1) ์„œ๋ก  ํ˜น์‹œ ์–ด๋– ํ•œ ์ผ์„ ํ•  ๋•Œ ๋ฐฐ๋ณด๋‹ค ๋ฐฐ๊ผฝ์ด ๋” ์ปค์กŒ๋˜ ๊ฒฝํ—˜์ด ์žˆ์œผ์‹ ๊ฐ€์š”? ์˜ˆ์ „์— ๋ฌธ๋“ ํ•ด๋ฌผํƒ•์ด๋ผ๋Š” ์š”๋ฆฌ๊ฐ€ ๋„ˆ๋ฌด ๋จน๊ณ  ์‹ถ์—ˆ๊ณ , ์ง‘ ๊ทผ์ฒ˜์—์„œ ํ•ด๋ฌผํƒ• ๊ฐ€๊ฒŒ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ง์ ‘ ํ•ด๋ฌผํƒ•์„ ๋งŒ๋“ค๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์„ ํ–ˆ์—ˆ๋Š”๋ฐ์š”. ํ•˜์ง€๋งŒ ํ•ด๋ฌผํƒ• ํ•œ ๊ทธ๋ฆ‡์„ ๋จน๊ธฐ ์œ„ํ•ด ๋น„์‹ผ ํ•ด์‚ฐ๋ฌผ๋“ค์„ ๊ตฌ๋งคํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ตฌ๋งคํ•œ ํ•ด์‚ฐ๋ฌผ๋“ค์„ ๋‹ค๋“ฌ๋Š” ์‹œ๊ฐ„์€ ๊ฝค ์˜ค๋ž˜ ๊ฑธ๋ ธ๋Š”๋ฐ์š”. ํ˜น์‹œ ์ž˜ ๋ชป ํ•ด๊ฐ์„ ํ•ด์„œ ๋ชจ๋ž˜๊ฐ€ ์”นํžˆ์ง€ ์•Š์„๊นŒ, ์ด ๋ถ€๋ถ„์€ ๋จน์–ด๋„ ๋˜๋Š” ๊ฑธ๊นŒ? ๊ณ ๋ฏผ์„ ํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์–ด์ฐŒ์–ด์ฐŒ ์š”๋ฆฌ ํ›„ ๋ง›์žˆ๊ฒŒ ๋จน์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ ๋‚จ๋Š” ์•„์‰ฌ์›€์€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. 15๋ถ„ ๋งŒ์— ๋จน๊ณ  ๋๋‚ด๋Š” ์ด ํ•œ ๊ทธ๋ฆ‡์„ ์œ„ํ•ด์„œ ์ด๋ ‡๊ฒŒ ๋งŽ์€ ๋ˆ๊ณผ ์ •์„ฑ์„ ์Ÿ๋Š” ๊ฒƒ์ด ์ •๋ง๋กœ ํšจ์œจ์ ์ธ ๊ฑด๊ฐ€? ์‹๋‹น์„ ์ฐพ์•„๊ฐ€์„œ ๋จน๊ฑฐ๋‚˜, ์ถ”๊ฐ€์˜ ๋ฐฐ๋‹ฌ๋น„๋ฅผ ๋‚ด๊ณ  ๋ฐฐ๋‹ฌ์„ ์‹œํ‚ค๋Š” ๊ฒƒ์ด..
https://yeon-kr.tistory.com/213
@Override
@Retryable(
    value = OptimisticLockingFailureException.class,
    maxAttempts = 3,
    backoff = @Backoff(delay = 100)
)
@Transactional(rollbackFor = Exception.class)
public void order(Order order) throws Exception {
      // 0-1. ์žฌ๊ณ ์ˆ˜๋Ÿ‰ ๊ฐ์†Œ
    decreaseProdQty(order.getOrdDtlList());
		...
package com.teamProject.syusyu.common.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.retry.annotation.EnableRetry;

@Configuration
@EnableRetry
public class RetryConfig {
    // ์ถ”๊ฐ€ ์„ค์ •์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์—ฌ๊ธฐ์— ์ •์˜
}

3ํšŒ ์žฌ์‹œ๋„ ํ›„์—๋„ ์ถฉ๋Œ์ด ๊ณ„์† ๋ฐœ์ƒํ•œ๋‹ค๋ฉด, ์‚ฌ์šฉ์ž์—๊ฒŒ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

@PostMapping("orders")
@ResponseBody
public ResponseEntity<String> order(@RequestBody OrderRequestDTO orderRequestDTO, @SessionAttribute int mbrId) {
    try {
        service.order(new Order(orderRequestDTO, mbrId));
    } catch (OptimisticLockingFailureException e) { // ๋‚™๊ด€๋ฝ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ–ˆ์„ ๋•Œ
        e.printStackTrace();
        return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
    } catch (Exception e) {
        e.printStackTrace();
        return new ResponseEntity<>("ADD_ERR", HttpStatus.BAD_REQUEST);
    }

    return new ResponseEntity<>("ADD_OK", HttpStatus.OK);
}

3. ๋น„๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด(Pessimistic Concurrency Control)

์ •์˜

์‚ฌ์šฉ์ž๋“ค์ด ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋™์‹œ์— ์ˆ˜์ •ํ•  ๊ฒƒ์œผ๋กœ ๊ฐ€์ •ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š” ์‹œ์ ์— Lock์„ ๊ฑธ๊ณ  ์กฐํšŒ ๋˜๋Š” ๊ฐฑ์‹ ์ฒ˜๋ฆฌ๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์ด๋ฅผ ์œ ์ง€ํ•œ๋‹ค.

์žฅ์ ๊ณผ ๋‹จ์ 

  • ์žฅ์ : ๋ฐ์ดํ„ฐ ์ˆ˜์ • ์ „ ์กฐํšŒ ์‹œ ๋ฏธ๋ฆฌ ๋ฝ์„ ๊ฑธ์–ด ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ๋™์‹œ์— ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝ ๋ชป ํ•˜๊ฒŒ ํ•จ์œผ๋กœ์จ ๋ฐ์ดํ„ฐ์˜ ์ •ํ•ฉ์„ฑ์„ ์œ ์ง€ํ•œ๋‹ค.
  • ๋‹จ์ :
    1. Lock์€ ์ฒซ ๋ฒˆ์งธ ์‚ฌ์šฉ์ž๊ฐ€ ํŠธ๋žœ์žญ์…˜์„ ์™„๋ฃŒํ•˜๊ธฐ ์ „๊นŒ์ง€ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๋“ค์ด ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๊ฒŒ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ฐ˜์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋Ÿ‰์ด ๊ฐ์†Œํ•˜๊ณ  ๋™์‹œ์„ฑ์ด ๋‚˜๋น ์งˆ ์ˆ˜ ์žˆ๋‹ค.
    1. ์‚ฌ์šฉ์ž๊ฐ€ ๋ชฐ๋ฆด ๊ฒฝ์šฐ, ๋ฝ์„ ์–ป๊ธฐ ์œ„ํ•ด ๋Œ€๊ธฐํ•˜๋ฉด์„œ ์ปค๋„ฅ์…˜์„ ๊ณ„์† ์ ์œ ํ•˜๊ฒŒ ๋˜์–ด ๊ทน๋‹จ์  ์ƒํ™ฉ์—์„œ๋Š” ์ปค๋„ฅ์…˜ ๋ถ€์กฑ ํ˜„์ƒ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

์ ์šฉ๋ฐฉ๋ฒ•

์žฌ๊ณ ์ˆ˜๋Ÿ‰์„ ์กฐํšŒํ•ด์˜ฌ ๋•Œ Lock์„ ๊ฑธ๊ณ  ํ•ด๋‹น ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ํŠธ๋žœ์žญ์…˜์ด ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์œ ์ง€ํ•œ๋‹ค.

<select id="selectProductQty" parameterType="int" resultType="ProdOptDTO">
    SELECT PO.PROD_ID, PO.OPT_COMB_NO, PO.INV_QTY
    FROM PROD_OPT PO
    WHERE OPT_COMB_NO IN
    <foreach collection="array" item="optCombNoArr" open="(" close=")" separator=",">
        #{optCombNoArr}
    </foreach>
		FOR UPDATE;
</select>

์ปค๋„ฅ์…˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•

์‚ฌ์‹ค ์ปค๋„ฅ์…˜ ๋ฌธ์ œ๋Š” ์ •๋ง ์ƒ๊ฐํ•ด๋ณด์ง€๋„ ์•Š์•˜๊ณ  ๊ณ ๋ คํ•ด๋ณผ ์ƒ๊ฐ๋„ ๋ชปํ•œ ์ฃผ์ œ์˜€๋Š”๋ฐ, ์ด๋ถ„์˜ ๊ธ€์„ ์ฝ๊ณ  ์ง„์ง€ํ•˜๊ฒŒ ์ƒ๊ฐํ•ด๋ณด๊ฒŒ๋˜์—ˆ๋‹ค.

๋™์‹œ์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ์„ ์œ„ํ•œ ๋ฝ ์„ ํƒ์— ๊ณ ๋ คํ•ด๋ณผ ๊ฒƒ๋“ค / ๋‚™๊ด€์  ๋ฝ๊ณผ ๋น„๊ด€์  ๋ฝ ์„ ํƒ ๋ฐฉ๋ฒ•?
Mysql InnoDB ์˜ RepeatableRead Mysql ์˜ ๊ธฐ๋ณธ Transaction isolate ์ˆ˜์ค€์€ RepeatableRead ์ด๋‹ค. RepeatableRead ๋Š” ํŠธ๋žœ์žญ์…˜์ด ์‹œ์ž‘๋œ ์‹œ์  ์ดํ›„๋กœ ์—ฌ๋Ÿฌ ๋ฒˆ Select Row ๋ฅผ ํ™•์ธํ•ด๋„ ๋™์ผํ•œ ๊ฐ’์„ ๊ฐ–๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. Mysql ์€ SnapShot์„ ์‚ฌ์šฉํ•ด์„œ ์ด๋ฅผ ๋ณด์žฅํ•œ๋‹ค. ํŠธ๋žœ์žญ์…˜๋งˆ๋‹ค ๋ณ„๋„์˜ ์Šค๋ƒ…์ƒท์„ ๊ธฐ๋กํ•˜์—ฌ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๊ณ  Commit ํ•ด๋„ ์ด ์Šค๋ƒ…์ƒท์„ ์ด์šฉํ•ด์„œ ๋™์ผํ•œ ๊ฐ’์„ ์ฝ๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค. Phantom read ๋ฌธ์ œ Repeatable Read ๋Š” ๋ฐ์ดํ„ฐ์˜ ์ถ”๊ฐ€, ์‚ญ์ œ์˜ ๋ณ€๊ฒฝ์€ ๋ง‰์ง€ ๋ชปํ•ด Phantom read ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ํ•œ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ์ „๊ณผ ๋‹ค๋ฅธ ์กฐํšŒ ๊ฒฐ๊ณผ row ์ˆ˜๋ฅผ ์กฐํšŒํ•˜๊ฒŒ ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. InnoDB..
https://www.blog.ecsimsw.com/entry/๋™์‹œ์„ฑ-ํ…Œ์ŠคํŠธ์™€-ํ•ด๊ฒฐ-๋ฐฉ์•ˆ

์˜ค๋ผํด์€ NOWAIT๊ณผ WAIT n ์˜ต์…˜์„ ์ œ๊ณตํ•ด, ํŠน์ • ์‹œ๊ฐ„๋งŒ ๋Œ€๊ธฐ ํ›„ ๋ฝ์„ ์–ป์ง€ ๋ชปํ•˜๋ฉด ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ํŠธ๋žœ์žญ์…˜์„ ์ข…๋ฃŒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ์˜คํžˆ๋ ค ๋™์‹œ์„ฑ์„ ์ฆ๊ฐ€์‹œํ‚ค๊ฒŒ๋˜๊ณ  ์ปค๋„ฅ์…˜๋„ ๊ณ„์† ๋ฌผ๊ณ  ์žˆ์ง€ ์•Š๋Š”๋‹ค.

<select id="selectProductQty" parameterType="int" resultType="ProdOptDTO">
    SELECT PO.PROD_ID, PO.OPT_COMB_NO, PO.INV_QTY
    FROM PROD_OPT PO
    WHERE OPT_COMB_NO IN
    <foreach collection="array" item="optCombNoArr" open="(" close=")" separator=",">
        #{optCombNoArr}
    </foreach>
		FOR UPDATE WAIT 3;
</select>

ํ•˜์ง€๋งŒ MySQL์—์„œ๋Š” WAIT n ์˜ต์…˜์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค. NOWAIT๊ณผ SKIP LOCKED ์˜ต์…˜๋งŒ ์ œ๊ณตํ•˜๋Š”๋ฐ, ํ˜„์žฌ ์ƒํ™ฉ์—์„œ๋Š” NOWAIT ์˜ต์…˜๋งŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ WAIT N์ด ์•„๋‹Œ NOWAIT ์˜ต์…˜์„ ์ ์šฉํ•  ๊ฒฝ์šฐ ๋ฝ ์‹œ๋„ ํ›„ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ์ ์œ  ์ค‘์ด๋ฉด ๋ฐ”๋กœ ์˜ˆ์™ธ๋ฅผ ๋˜์ ธ ์žฌ์‹œ๋„ ๋น„์šฉ์ด ํฌ๋‹ค. ์ด๋ ‡๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋‚™๊ด€๋ฝ์ด๋ž‘ ๋ฌด์Šจ ์ฐจ์ด๊ฐ€ ์žˆ๋‚˜ ์‹ถ๊ธฐ๋„ ํ•˜๋‹ค.

๋น„๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ์ ์šฉํ•ด ์ปค๋„ฅ์…˜์ด ๋ถ€์กฑํ•˜๊ฒŒ ๋˜๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด, ์ปค๋„ฅ์…˜ ๋ถ€์กฑ ๋ฌธ์ œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๊ธฐ๋„ํ•˜๊ณ .. ๋‚˜๋ผ๋ฉด DB ์ปค๋„ฅ์…˜์„ ๋Š˜๋ฆฌ๋Š” ๋ฐฉ๋ฒ•์„ ๊ณ ๋ คํ•  ๊ฒƒ ๊ฐ™๋‹ค.

์ ์šฉํ•˜๋ฉด์„œ ์‚ฝ์งˆ ๊ณผ์ •์ด ๊ถ๊ธˆํ•˜์‹  ๋ถ„๋“ค์€ ์•„๋ž˜ ์ฐธ๊ณ ..

4. ๋ถ„์‚ฐ ๋ฝ

ํ•˜๋‚˜์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์—ฌ๋Ÿฌ DB๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

โ—์ ์šฉํ•œ ๋ฐฉ๋ฒ•๊ณผ ์„ ํƒ ๊ธฐ์ค€, ํ…Œ์ŠคํŠธ


Serializable์€ ๋ฐ๋“œ๋ฝ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ๊ณผ ์‹ฌ๊ฐํ•œ ์„ฑ๋Šฅ ์ €ํ•˜์˜ ์ด์œ ๋กœ ์ œ์™ธํ–ˆ๋‹ค. ๋ถ„์‚ฐ ๋ฝ๋„ ํ˜„์žฌ ํ”„๋กœ์ ํŠธ๊ฐ€ Redis ๊ฐ™์€ ๋ถ„์‚ฐ ์บ์‹œ ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , ๋ชจ๋“  ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๊ฐ€ ๋‹จ์ผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋‚ด์—์„œ ์ด๋ฃจ์–ด์ง€๋ฏ€๋กœ ๊ณ ๋ ค ๋Œ€์ƒ์ด ์•„๋‹ˆ์—ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‚™๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด์™€ ๋น„๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•ด์•ผ ํ–ˆ๋‹ค.

๋‚™๊ด€๋ฝ vs. ๋น„๊ด€๋ฝ

๋งŽ์€ ๋ธ”๋กœ๊ทธ์—์„œ ์ผ๋ฐ˜์ ์œผ๋กœ ์ž์›์˜ ๊ฒฝํ•ฉ์ด ๋นˆ๋ฒˆํ•˜๋ฉด ๋น„๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด, ๋นˆ๋ฒˆํ•˜์ง€ ์•Š์œผ๋ฉด ๋‚™๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋ผ๊ณ  ํ•˜๋˜๋ฐ.. ๋‚˜์˜ ์ƒํ™ฉ์— ๋Œ€์ž…ํ•ด ์ƒ๊ฐํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.

๋‚ด ํ”„๋กœ์ ํŠธ์—์„œ ์ฃผ๋ฌธ ๋กœ์ง์€ ์žฌ๊ณ ์ˆ˜๋Ÿ‰ ์กฐํšŒ ํ›„ ๊ตฌ๋งค ๊ฐ€๋Šฅํ•œ ์ƒํƒœ๋ฅผ ๊ฒ€์ฆํ•˜๊ณ  ๋ฐ”๋กœ ์žฌ๊ณ ์ˆ˜๋Ÿ‰์„ ๊ฐ์†Œ์‹œํ‚ค๊ธฐ ๋•Œ๋ฌธ์—, ์กฐํšŒ์™€ ์ˆ˜์ • ์‹œ๊ฐ„ ๊ฐ„๊ฒฉ์ด ๋งค์šฐ ์งง๋‹ค.

๋‚™๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ ๋ฝ์„ ์•„์˜ˆ ์•ˆ ๊ฑฐ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ์กฐํšŒ ์‹œ ๋ฝ์„ ์•ˆ ๊ฑธ๊ณ  ์ˆ˜์ • ์‹œ์—๋Š” ๋ฝ์„ ๊ฑธ๊ฒŒ๋œ๋‹ค. ์ด๋Ÿฐ ์ƒํ™ฉ์—์„œ์˜ ๋‚™๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด์˜ ์ ์šฉ์€ Lock์ด ์œ ์ง€๋˜๋Š” ์‹œ๊ฐ„์ด ์งง์•„์„œ ๋™์‹œ์„ฑ์„ ๋†’์ด๋Š”๋ฐ ์œ ๋ฆฌํ•˜๋‹ค๋Š” ์žฅ์ ์„ ํ™œ์šฉํ•˜์ง€ ๋ชปํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

๋˜ํ•œ, ๋‚™๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด์˜ ๊ฒฝ์šฐ ํ˜„์žฌ ๊ฐ’๊ณผ ์ด์ „์— ์ฝ์€ ๊ฐ’์˜ ๋ถˆ์ผ์น˜ ์‹œ ์žฌ์‹œ๋„ํ•˜๋Š” ๋กœ์ง์„ ์ถ”๊ฐ€๋กœ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ํŠนํžˆ ํŠน๊ฐ€์ƒํ’ˆ์ด๋‚˜ ํ•œ์ •์žฌ๊ณ  ๊ฐ™์€ ๊ฒฝ์šฐ ์ž์› ๊ฒฝํ•ฉ์ด ๋นˆ๋ฒˆํ•˜๊ฒŒ ๋ฐœ์ƒ๋  ๊ฒƒ์ด๊ณ  ๋ฌดํ•œ์œผ๋กœ ์žฌ์‹œ๋„ ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜๋Š” ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ •ํ•ด๋‘” ์žฌ์‹œ๋„ ํšŸ์ˆ˜๋ฅผ ๋„˜์–ด๊ฐ€๊ฒŒ๋˜๋ฉด ์ฃผ๋ฌธ์ด ์‹คํŒจํ•˜๊ฒŒ๋˜์–ด ๊ณ ๊ฐ์ด ๋ถˆํŽธํ•จ์„ ๊ฒช๊ฒŒ๋œ๋‹ค.

์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ

์ด๋Ÿฐ ๋‚ด ๊ฐ€์ •์ด ์ •๋ง์ธ์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์‹ค์ œ๋กœ ์กฐํšŒ์— ๋ฝ์„ ๊ฑธ์—ˆ์„ ๋•Œ์™€ ๋ฝ์„ ๊ฑธ์ง€ ์•Š์•˜์„ ๋•Œ์˜ ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด์•˜๋‹ค.

์žฌ๊ณ  499๊ฐœ ์ƒํƒœ์—์„œ 100๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ผํ•œ 5๊ฐœ ์ƒํ’ˆ์— ๋Œ€ํ•œ ์ด 500๊ฐœ์˜ ์ฃผ๋ฌธ์„ ์‹œ๋„ํ•œ ๊ฒฐ๊ณผ(๊ฐ๊ฐ 10๋ฒˆ์”ฉ ๋Œ๋ ค๋ณด๊ณ  ํ‰๊ท ์น˜๋ฅผ ๋‚ด๋ณด์•˜๋‹ค.)

์กฐํšŒ์— Lock์„ ๊ฑธ์ง€ ์•Š์•˜์„ ๋•Œ์˜ ํ‰๊ท  ์ฒ˜๋ฆฌ ์‹œ๊ฐ„์€ 5.8์ดˆ์˜€๊ณ , ๋น„๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ๋Š” 5.9์ดˆ๋กœ ๋‚˜ํƒ€๋‚ฌ๋‹ค.

  1. ์กฐํšŒ์— Lock์„ ๊ฑธ์ง€ ์•Š์•˜์„ ๋•Œ

    5.8566 = (5.931+6.61+5.858+5.824+5.787+5.910+5.518+5.635+5.845+5.648)/10

  1. ์กฐํšŒ์— Lock์„ ๊ฑธ์—ˆ์„ ๋•Œ

    5.9623 = (6.52+5.528+5.867+5.999+6.482+5.769+5.931+5.970+5.770+5.787)/10

ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ, ์กฐํšŒ์— Lock์„ ๊ฑธ์—ˆ์„ ๋•Œ๋Š” ํ‰๊ท  5.9์ดˆ. ์กฐํšŒ์— Lock์„ ๊ฑธ์ง€ ์•Š์•˜์„ ๋•Œ๋Š” ํ‰๊ท  5.8์ดˆ๋กœ ํ‰๊ท  ์ฒ˜๋ฆฌ ์‹œ๊ฐ„์˜ ํฐ ์ฐจ์ด๊ฐ€ ์—†์—ˆ๋‹ค. ๋‚ด๊ฐ€ ๊ฐ€์ •ํ–ˆ๋˜ Lock์ด ์œ ์ง€๋˜๋Š” ์‹œ๊ฐ„์ด ๋น„์Šทํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ์ฐจ์ด๋„ ๊ทธ๋ ‡๊ฒŒ ํฌ์ง€ ์•Š์„ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ๊ฐ€์ •์— ํ™•์‹ ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ๊ตณ์ด ๋‚ด ์ƒํ™ฉ์—์„œ ๊ฒฝํ•ฉ์ด ๋ฐœ์ƒ๋  ๋•Œ ์ฒ˜๋ฆฌ๋น„์šฉ์ด ํฐ ๋‚™๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ์„ ํƒํ•ด์„œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๊ณ  ์ƒ๊ฐ๋˜์–ด ๋น„๊ด€์  ๋™์‹œ์„ฑ ์ œ์–ด๋ฅผ ์„ ํƒํ•ด ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์˜€๋‹ค.

๊ฒฝํ•ฉ์ด ์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ๋น„๊ด€์  ๋ฝ, ๊ทธ๋ ‡์ง€ ์•Š์„ ๋•Œ๋Š” ๋‚™๊ด€๋ฝ์„ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๋ผ๋Š” ์ด๋ก ์ ์ธ ๊ณต์‹๋ณด๋‹ค๋Š” ํ˜„์žฌ ๋‚ด ํ”„๋กœ์ ํŠธ ์ƒํ™ฉ์„ ๊ณ ๋ คํ•ด ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

๊ตฌํ˜„

์žฌ๊ณ ์ˆ˜๋Ÿ‰์„ ์กฐํšŒํ•ด์˜ค๋Š” ์ฟผ๋ฆฌ๋ฌธ์— FOR UPDATE ๊ตฌ๋ฌธ์„ ์จ ๋กœ์šฐ ๋ฝ์„ ๊ฑธ์–ด์ฃผ์–ด ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. (์˜ค๋ผํด์ด๋ผ๋ฉด for update wait 3 ๊ตฌ๋ฌธ์„ ์จ์ฃผ์—ˆ์„ ๊ฒƒ ๊ฐ™๋‹ค.)

<select id="selectProductQty" parameterType="int" resultType="ProdOptDTO">
    SELECT PO.PROD_ID, PO.OPT_COMB_NO, PO.INV_QTY
    FROM PROD_OPT PO
    WHERE OPT_COMB_NO IN
    <foreach collection="array" item="optCombNoArr" open="(" close=")" separator=",">
        #{optCombNoArr}
    </foreach>
    FOR UPDATE
</select>

๐Ÿ”œ ๋‚˜๊ฐ€๋ฉฐ


์ด๋ฒˆ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ณผ์ •์—์„œ ์ด๋ก ์ ์œผ๋กœ ๊ณต๋ถ€ํ•œ ์ง€์‹์„ ์‹ค๋ฌด์— ์ง์ ‘ ์ ์šฉํ•ด๋ณด๋Š” ๊ฒฝํ—˜์ด ์ •๋ง์ •๋ง์ •๋ง ์ค‘์š”ํ•˜๋‹ค๋Š” ๊ฑธ ๊นจ๋‹ฌ์•˜๋‹ค. ๋‹จ์ˆœํžˆ โ€˜๊ณต๋ถ€ํ–ˆ๋‹คโ€™์—์„œ ๋๋‚˜๋ฉด ์•ˆ ๋œ๋‹ค. ์‹ค์ œ๋กœ ์ ์šฉ์„ ํ•ด๋ด์„œ ์™„์ „ํžˆ ๋‚ด๊ฑธ๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค. ์ด๋ก ๋งŒ ์•Œ๊ณ ์žˆ๋Š” ๊ฑด ์˜๋ฏธ์—†๊ณ  ๋ฐฐ์šด ๊ฑธ ์‹ค์ œ๋กœ ๊บผ๋‚ด์„œ ์“ธ ์ค„ ์•Œ์•„์•ผ ํ•œ๋‹ค.

2์›”๋ถ€ํ„ฐ ์ง€๊ธˆ๊นŒ์ง€ ์ •๋ง ๋งŽ์€ ๊ณต๋ถ€๋ฅผ ํ•ด์™”์ง€๋งŒ, ์‹ค์ œ๋กœ ์ ์šฉํ•ด๋ณธ ๊ฑด ์†์— ๊ผฝ์•˜๊ณ  ๊ทธ๋ ‡๋‹ค๋ณด๋‹ˆ ๋‚ด ๊ธฐ์–ต์—๋„ ๊ฐ•๋ ฌํ•˜๊ฒŒ ๋‚จ์ง€๋Š” ์•Š์•˜๋˜ ๊ฒƒ ๊ฐ™๋‹ค.(๋ฌผ๋ก  ๋ณต์Šต์„ ์•ˆ ํ•ด์„œ์ธ ๊ฒƒ๋„ ์žˆ๋‹ค ใ…Žใ…Ž..)

์ด๋ฒˆ์— ๋™์‹œ์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ์ดํ„ฐ ์ค‘์‹ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค๊ณ„ 7์žฅ ํŠธ๋žœ์žญ์…˜ ๋ถ€๋ถ„์„ ๋‹ค์‹œ ์ฝ์œผ๋ฉด์„œ, ๋‚ด๊ฐ€ ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๊ณ  ๊ทธ๊ฑธ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋Œ€์ž…ํ•˜๋ฉด์„œ ์ฝ์œผ๋‹ˆ๊นŒ ์ดํ•ด๊ฐ€ ๋” ๊นŠ์–ด์ง„ ๊ฑธ ๊ฒฝํ—˜ํ–ˆ๋‹ค. ๊ทธ๋™์•ˆ ์ˆ˜์—…๋“ฃ๊ณ  ๊ทธ๋‚ด์šฉ ์ตํžˆ๋А๋ผ ๋ฐ”๋น ์„œ ๋ฐฐ์› ๋˜ ๋‚ด์šฉ์„ ์‹ค์ „์— ์ ์šฉํ•˜์ง€ ๋ชปํ–ˆ์—ˆ๋Š”๋ฐ, ์‹ค์ œ๋กœ ์ด๋ ‡๊ฒŒ ์จ๋จน์œผ๋‹ˆ๊นŒ ๋„ˆ๋ฌด๋„ˆ๋ฌด๋„ˆ๋ฌด ์žฌ๋ฐŒ์—ˆ๋‹ค ์‹œ๊ฐ„ ๊ฐ€๋Š” ์ค„ ๋ชจ๋ฅด๊ณ  ๋น ์ ธ๋“ค์—ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค

์•ž์œผ๋กœ๋Š” ์–ด๋–ค ๊ฑธ ๋ฐฐ์šฐ๊ฑฐ๋‚˜ ์ฑ…์„ ์ฝ๋”๋ผ๋„ โ€˜๋ชฉ์ โ€™๊ณผ โ€˜์˜๋„โ€™๋ฅผ ๋ถ„๋ช…ํ•˜๊ฒŒ ์„ค์ •ํ•˜๊ณ  ์ฝ์ž. ๊ทธ๋ฆฌ๊ณ  ๊ณต๋ถ€ํ–ˆ๋‹ค๋Š”๊ฑฐ์—์„œ ๋๋‚ด์ง€๋ง๋„ ์ž‘์€ ๊ฑฐ๋ผ๋„ ์‹ค์ œ๋กœ ์ ์šฉํ•ด์„œ ๋‚ด๊ฒƒ์œผ๋กœ ๋งŒ๋“ค๊ธฐ!

์ฑ…์„ ์ฝ์–ด๋„ ์ด๋Ÿฐ ๋ฌธ์ œ๋“ค์ด ๋‚ด๊ฐ€ ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ๋Š” ์‹œ์Šคํ…œ์—์„œ๋„ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ๋“ค์ธ์ง€, ๋‚˜์˜ ์ƒํ™ฉ์—์„œ ๋Œ€์ž…ํ•ด๋ณด์ž. ๊ทธ๋ƒฅ ์ง€์‹์„ ์–ป๋Š” ๊ฒƒ๋ฟ๋งŒ์ด ์•„๋‹Œ ๋‚ด๊ฐ€ ์ด๊ฑธ ๋ฐฐ์›Œ์„œ ์–ด๋””์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์ด๋Ÿฐ ์ ์šฉ์ ๋“ค์„ ์ƒ๊ฐํ•˜๋ฉด์„œ ์ฝ๋Š” ๊ฒŒ ์ค‘์š”ํ•˜๋‹ค๋Š” ๊ฒƒ๋„ ๋А๊ผˆ๋‹ค.

๋ฐ์ค‘์—์„ค์—์„œ๋„ ๋™์‹œ์„ฑ๋ฟ๋งŒ์•„๋‹ˆ๋ผ ๋‹ค์–‘ํ•œ ๋ฌธ์ œ๋“ค์— ๋Œ€ํ•ด ๋ฐฐ์šด ๋‚ด์šฉ์„ ๋” ์ ์šฉํ•ด๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

๋‹ค์‹œ ํ•œ๋ฒˆ ๋А๋ผ๋Š” ๊ฑฐ์ง€๋งŒ ๋ฉง๋ผ์ง€ ์ฑ…์€ ์ €์ž์˜ ์‹ค๋ฌด ๊ฒฝํ—˜์ด ์ž˜ ๋…น์•„์žˆ๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ์žˆ๊ณ  ์‹œ๋„ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•๋“ค์€ ๋ฌด์—‡์ด๋ฉฐ ์ด๋Ÿฐ ๋ฌธ์ œ ํ•ด๊ฒฐ ๊ณผ์ •์ด ์ƒ์„ธํ•˜๊ฒŒ ๋‚˜์™€์žˆ์–ด์„œ ๋งŽ์€ ๋„์›€์ด ๋๋‹ค.

๐Ÿ“–ย Reference



Uploaded by N2T