์ฃผ๋ฌธ ์ ์ฌ๊ณ ์๋์ด ๋ง์ด๋์ค๊ฐ ๋๋ ๋์์ฑ ๋ฌธ์ ํด๊ฒฐํ๊ธฐ
๋์์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ฉฐ ๊ฒช์ ๋ฌธ์ ๋ค
๐ฉย ๋ค์ด๊ฐ๋ฉฐ
์ค๋ฌด์์๋ ์ ๋ง ๋ค์ํ๊ณ ์์์น ๋ชปํ ๋ฌธ์ ๋ค์ ํด๊ฒฐํด์ผ ํ๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ฌ์ ์ ์ด๋ค ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ง ๊ฐ์ ์ ํด๋ณด๊ณ , ํด๊ฒฐํด๋ณด๋ ๊ฒฝํ์ด ๊ต์ฅํ ์ค์ํ๋ค๊ณ ์๊ฐํ๋ค.
ํ ํ๋ก์ ํธ๋ก ๊ฐ๋ฐํ ์ผํ๋ชฐ ํ๋ก์ ํธ์์ ์ด๋ค ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์๊น๋ฅผ ๊ณ ๋ฏผํด๋ณด์๋๋ฐ, ์ผ๋ง ์ ์ ์ฝ์ โ๋ฐ์ดํฐ ์ค์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ค๊ณโ๋ผ๋ ์ฑ ์ 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๊ฐ โ 0๊ฐ
- ์ฃผ๋ฌธ ํธ๋์ญ์ 2 ์์ ๋ฐ ์ค๋ ์ท ์์ฑ: ํธ๋์ญ์ 2๊ฐ ์์๋ ์์ ์์ ์ฌ๊ณ ์๋์ 1๊ฐ์ด๊ธฐ ๋๋ฌธ์ ์ฌ๊ณ ์๋์ด 1๊ฐ์ธ ์ค๋ ์ท์ ์์ฑ
- ํธ๋์ญ์ 1์์ ์์ฑํ ๋ฐ์ดํฐ ์ปค๋ฐ: DB์ ์๊ตฌ์ ์ผ๋ก ๋ฐ์
- ํธ๋์ญ์ 2 ์ฌ๊ณ ์๋ ๊ฒ์ฆ: ํธ๋์ญ์ 1์์ ๋ณ๊ฒฝํ ์ฌ๊ณ ์๋ ๋ฐ์ดํฐ๊ฐ ์ปค๋ฐ์ด ๋์์ง๋ง ๋ด ์ค๋ ์ท(์ฌ๊ณ ์๋ 1๊ฐ)์ ๊ธฐ๋ฐ์ผ๋ก ์ฌ๊ณ ์๋์ ๊ฒ์ฆํ๋ค. ์ด๋ก์ธํด ์ฌ๊ณ ์๋ ๊ฒ์ฆ์ ํต๊ณผํ๋ค.
- ํธ๋์ญ์ 2์์ ์ฌ๊ณ ์๋์ ๊ฐ์ & ์ฃผ๋ฌธ ์์ฑ: ์ฌ๊ณ ์๋ 0๊ฐ โ -1๊ฐ
- ํธ๋์ญ์ 2์์ ์์ฑํ ๋ฐ์ดํฐ ์ปค๋ฐ: ์ฌ๊ณ ์๋์ด -1๊ฐ์ธ์ฑ๋ก DB์ ์๊ตฌ์ ์ผ๋ก ๋ฐ์
Repeatable Read๋ ์ค๋ ์ท ๊ฒฉ๋ฆฌ์ด๊ณ , MVCC๋ก ๊ตฌํ๋์ด์๋ค. ์ด๋ฅผ ํตํด ์ผ๊ด๋ ๋ณด๊ธฐ(Read Consistency)๋ฅผ ์ ์งํ๊ฒ ํด์ค๋ค. ์์ธํ ๋ด์ฉ์ ์๋๋ฅผ ์ฐธ๊ณ .

๐ช๐ปย ํด๊ฒฐ ๋ฐฉ๋ฒ
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)
์ ์
๋ง์ง๋ง์ผ๋ก ์ฝ์ ํ๋ก ๋ณ๊ฒฝ๋์ง ์์์ ๋๋ง ๊ฐฑ์ ์ ํ์ฉํจ์์จ ๋์์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ด๋ค.
์๋๋ ๋จผ์ ๊ฒ์ฌ๋ฅผ ํ๊ณ ๋ณ๊ฒฝ ์๋๋ฅผ ํด์ผ ํ๋๋ฐ ์ค๋ง ๋ณ๊ฒฝ๋์ด์๊ฒ ์ด? ํ๊ณ ๋๊ด์ ์ผ๋ก ์ ๊ทผํด, ๋ฐ์ดํฐ๋ฅผ ์ ๋ฐ์ดํธํ๊ธฐ ์ ์ ํด๋น ๋ฐ์ดํฐ๊ฐ ๋ง์ง๋ง์ผ๋ก ์ฝํ ํ ๋ณ๊ฒฝ๋์๋์ง ํ์ธ. ๋ณ๊ฒฝ๋์๋ค๋ฉด ์ถฉ๋์ ๊ฐ์งํด ํธ๋์ญ์ ์ ๋กค๋ฐฑํ๋ค.
์ฅ์ ๊ณผ ๋จ์
- ์ฅ์ : ์ฑ๋ฅ ์ธก๋ฉด์์ ๋น๊ด์ ๋ฝ๋ณด๋ค ์ผ๋ฐ์ ์ผ๋ก ์ฐ์ํ ๊ฒ์ผ๋ก ์๋ ค์ ธ ์๋ค. ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ๋ ๋ฝ์ ๊ฑธ์ง ์๊ธฐ ๋๋ฌธ์, ์ฌ๋ฌ ์ฌ์ฉ์๊ฐ ๋์์ ๋ฐ์ดํฐ์ ์ ๊ทผํ ์ ์๋ค.
- ๋จ์ :
- ์์ ๊ฒฝํฉ์ด ๋น๋ฒํ๊ฒ ๋ฐ์ํ๋ ์ํฉ์์ ์คํจํ์ ๋์ ์ฒ๋ฆฌ ๋น์ฉ์ด ๋๋ค. ํ์ฌ ๊ฐ์ด ์ด์ ์ ์ฝ์ ๊ฐ๊ณผ ์ผ์นํ์ง ์์ผ๋ฉด read-modify-write ์ฃผ๊ธฐ๋ฅผ ์ฌ์๋ํด์ผ ํ๋ค.
- ๋์ผํ ์ํ์ ์ฃผ๋ฌธ์ด ๋ชฐ๋ฆด ๊ฒฝ์ฐ ์ถฉ๋์ด ๋ฐ์ํด ํธ๋์ญ์ ์ด ๋กค๋ฐฑ๋ ๊ฒ์ด๊ณ ์ฌ์๋ ๋ก์ง์ ๊ตฌํํ๊ฒ ์ง๋ง ๋ฌดํ์ผ๋ก ์ฌ์๋ ์ฒ๋ฆฌ๋ฅผ ํ ์๋ ์๊ธฐ ๋๋ฌธ์ ์ ํด๋ ์ฌ์๋ ํ์๋ฅผ ๋์ด๊ฐ๊ฒ๋๋ฉด ์ฃผ๋ฌธ์ด ์คํจํ๊ฒ๋์ด ๊ณ ๊ฐ์ด ๋ถํธํจ์ ๊ฒช๊ฒ๋๋ค.
์ ์ฉ๋ฐฉ๋ฒ
- ํด๋น ์ปฌ๋ผ๋ง ๋น๊ต
์ฒ์ ์ฌ๊ณ ์๋์ ์กฐํํด์ค๊ณ ๋ง์ง๋ง์ผ๋ก ์ฝ์ ํ๋ก ๋ณ๊ฒฝ๋์ง ์์์ ๋๋ง ๊ฐฑ์ ์ ํ์ฉํจ์์จ ๋์์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ด๋ค.
์ฌ๊ณ ์๋ ๊ฐ์ ๋ก์ง์ ์ฒ์ ์ฝ์ด์์ ๋น์์ ์ฌ๊ณ ์๋์ ์ฌ๊ณ ์๋์ ๊ฐ์์ํค๋ ์ฟผ๋ฆฌ์ param์ผ๋ก ๋๊ฒจ์ค์ผ ํด ์ถ๊ฐ ์ฝ๋ ์์ ์ด ํ์ํ๋ค๋ ๋จ์ ์ด ์๋ค.
UPDATE prod_opt SET INV_QTY = INV_QTY - #{new_qty} WHERE OPT_COMB_NO = #{optCombNo} AND INV_QTY = #{old_qty} # ๋ง์ง๋ง ์ฝ์ ์ดํ๋ก ๋ณ๊ฒฝ๋์ง ์์์ ๋๋ง
- ๋ณ๊ฒฝ์ผ์ = ํ์์คํฌํ
๋ฐ์ดํฐ์ ์ต์ข ๋ณ๊ฒฝ ์๊ฐ์ ํ์์คํฌํ๋ก ๊ด๋ฆฌํ๊ณ , ์ด๋ฅผ ํตํด ๋ณ๊ฒฝ ์ฌ๋ถ๋ฅผ ํ๋จํ๋ ๋ฐฉ๋ฒ์ด๋ค.
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๋ฅผ ์ด์ฉํด์ผ ํ๋ค.
๋ณ๊ฒฝ ํฌ์ธํธ๊ฐ
- UPD_DTTM ์ปฌ๋ผ์ ๋ฐ์ดํฐ ํ์ TIMESTAMP โ TIMESTAMP(3) ๋ณ๊ฒฝ
- ๋ณ๊ฒฝ์ผ์๋ฅผ now() โ CURRENT_TIMESTAMP(3) ๋ณ๊ฒฝ
์ด๋ ๊ฒ 2๊ตฐ๋ฐ๋ ๋๊ณ , ์ถ๊ฐ ์ฝ๋ ์์ ์ด ๋ง์์ง๊ณ ๊ด๋ฆฌ ํฌ์ธํธ๊ฐ ๋์ด๋๊ฒ๋๋ค๋ ๋จ์ ์ด ์๋ค.
๊ด๋ จํด์๋ ์๋๋ฅผ ์ฐธ๊ณ
์ ์ฉํ๋ฉด์ ์ฝ์ง ๊ณผ์ ์ด ๊ถ๊ธํ์ ๋ถ๋ค์ ์๋ ๊ธ ์ฐธ๊ณ ,,
- ๋ฒ์ ์ปฌ๋ผ
ํธ๋์ญ์ ์ด ์๊ฐ๋ ํ ๋ฒ์ ์ด ๋ณ๊ฒฝ๋์๋์ง ํ์ธํด ๋ฒ์ ์ด ๊ฐ์์ผ 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๋ ๊ฐ์ด + ๋๋ ์ฟผ๋ฆฌ๋ฅผ ์ถ๊ฐํด์ค์ผ ํ๋ ๋จ์ ์ด ์๋ค.
- JPA์ @Version
JPA๋ฅผ ํ์ฉํ๋ฉด ๋๊ด์ ๋์์ฑ ์ ์ด๋ฅผ @Version ์ ๋ํ ์ด์ ์ผ๋ก ์ฝ๊ฒ ๊ตฌํํ ์ ์๋ค. ํ์ง๋ง MyBatis๋ง์ ์ฌ์ฉํ๋ ๋ด ํ๋ก์ ํธ์๋ ๋น์ฅ ์ ์ฉ์ด ์ด๋ ต๋ค.
์๋ ๋น๊ต
๊ตฌ๋งคํ๋ ค๋ ์๋์ด ํ์ฌ ์๋๋ณด๋ค ๋ง์ด ๋จ์์๋์ง๋ฅผ ์ฒดํฌํ์ฌ ๋๊ด์ ๋์์ฑ ์ ์ด๋ฅผ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ด๋ค.
์ถ๊ฐ ์ฝ๋ ์์ด๋ ๊ฐ์ฅ ์ฝ๊ณ ๊น๋ํ๊ฒ ๊ตฌํ ๊ฐ๋ฅ.
<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ํ๋ก ์ ํํ์๋ค.

@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์ ๊ฑธ๊ณ ์กฐํ ๋๋ ๊ฐฑ์ ์ฒ๋ฆฌ๊ฐ ์๋ฃ๋ ๋๊น์ง ์ด๋ฅผ ์ ์งํ๋ค.
์ฅ์ ๊ณผ ๋จ์
- ์ฅ์ : ๋ฐ์ดํฐ ์์ ์ ์กฐํ ์ ๋ฏธ๋ฆฌ ๋ฝ์ ๊ฑธ์ด ๋ค๋ฅธ ํธ๋์ญ์ ์ด ๋์์ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝ ๋ชป ํ๊ฒ ํจ์ผ๋ก์จ ๋ฐ์ดํฐ์ ์ ํฉ์ฑ์ ์ ์งํ๋ค.
- ๋จ์ :
- Lock์ ์ฒซ ๋ฒ์งธ ์ฌ์ฉ์๊ฐ ํธ๋์ญ์ ์ ์๋ฃํ๊ธฐ ์ ๊น์ง ๋ค๋ฅธ ์ฌ์ฉ์๋ค์ด ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ ์ ์๊ฒ ๋ง๋ค๊ธฐ ๋๋ฌธ์ ์ผ๋ฐ์ ์ผ๋ก ์ฒ๋ฆฌ๋์ด ๊ฐ์ํ๊ณ ๋์์ฑ์ด ๋๋น ์ง ์ ์๋ค.
- ์ฌ์ฉ์๊ฐ ๋ชฐ๋ฆด ๊ฒฝ์ฐ, ๋ฝ์ ์ป๊ธฐ ์ํด ๋๊ธฐํ๋ฉด์ ์ปค๋ฅ์ ์ ๊ณ์ ์ ์ ํ๊ฒ ๋์ด ๊ทน๋จ์ ์ํฉ์์๋ ์ปค๋ฅ์ ๋ถ์กฑ ํ์์ด ๋ฐ์ํ ์ ์๋ค.
์ ์ฉ๋ฐฉ๋ฒ
์ฌ๊ณ ์๋์ ์กฐํํด์ฌ ๋ 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>
์ปค๋ฅ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ
์ฌ์ค ์ปค๋ฅ์ ๋ฌธ์ ๋ ์ ๋ง ์๊ฐํด๋ณด์ง๋ ์์๊ณ ๊ณ ๋ คํด๋ณผ ์๊ฐ๋ ๋ชปํ ์ฃผ์ ์๋๋ฐ, ์ด๋ถ์ ๊ธ์ ์ฝ๊ณ ์ง์งํ๊ฒ ์๊ฐํด๋ณด๊ฒ๋์๋ค.

์ค๋ผํด์ 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์ด๋ก ๋ํ๋ฌ๋ค.
- ์กฐํ์ Lock์ ๊ฑธ์ง ์์์ ๋
5.8566
= (5.931+6.61+5.858+5.824+5.787+5.910+5.518+5.635+5.845+5.648)/10
- ์กฐํ์ 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
- ๋์์ฑ ๋ฌธ์ ํด๊ฒฐ์ ์ํ ๋ฝ ์ ํ์ ๊ณ ๋ คํด๋ณผ ๊ฒ๋ค / ๋๊ด์ ๋ฝ๊ณผ ๋น๊ด์ ๋ฝ ์ ํ ๋ฐฉ๋ฒ?๋์์ฑ ๋ฌธ์ ํด๊ฒฐ์ ์ํ ๋ฝ ์ ํ์ ๊ณ ๋ คํด๋ณผ ๊ฒ๋ค / ๋๊ด์ ๋ฝ๊ณผ ๋น๊ด์ ๋ฝ ์ ํ ๋ฐฉ๋ฒ?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/๋์์ฑ-ํ ์คํธ์-ํด๊ฒฐ-๋ฐฉ์
- [DB] ๋์์ฑ ๋ฌธ์ ํด๊ฒฐ๋ฐฉ๋ฒ[DB] ๋์์ฑ ๋ฌธ์ ํด๊ฒฐ๋ฐฉ๋ฒ๋์์ฑ ๋ฌธ์ ๊ฐ ๋ฌด์์ด๊ณ ํด๊ฒฐ๋ฐฉ๋ฒ์ ๋ํ์ฌ ์์๋ณด๋๋ก ํ๋ค.
https://chrisjune-13837.medium.com/db-๋์์ฑ-๋ฌธ์ -ํด๊ฒฐ๋ฐฉ๋ฒ-f5e52e2e3
Uploaded by N2T