[Project] NonUniqueResultException ๋ฐœ์ƒ

Updated:

Categories:

Tags: ,

๐Ÿ“Œ ๊ฐœ์ธ์ ์ธ ๊ณต๊ฐ„์œผ๋กœ ๊ณต๋ถ€๋ฅผ ๊ธฐ๋กํ•˜๊ณ  ๋ณต์Šตํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋ธ”๋กœ๊ทธ์ž…๋‹ˆ๋‹ค.
์ •ํ™•ํ•˜์ง€ ์•Š์€ ์ •๋ณด๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฐธ๊ณ ๋ฐ”๋ž๋‹ˆ๋‹ค :๐Ÿ˜ธ
[ํ‹€๋ฆฐ ๋‚ด์šฉ์€ ๋Œ“๊ธ€๋กœ ๋‚จ๊ฒจ์ฃผ์‹œ๋ฉด ๋ณต๋ฐ›์œผ์‹ค๊ฑฐ์—์š”]


์˜ค๋Š˜ OrderService ๋ถ€๋ถ„ ๋งˆ๋ฌด๋ฆฌํ•˜๋ ค๊ณ  ํ…Œ์ŠคํŠธํ•ด๋ณด๋‹ค๊ฐ€ ๋จธ๋ฆฌ๊ฐ€ ๋ตํ•ด์กŒ๋‹ค. ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ๋ณด๋Š”๋ฐ javax.persistence.NonUniqueResultException: query did not return a unique result: 2๋ผ๋Š” ์—๋Ÿฌ๊ฐ€ ๋– ์„œ ๋„๋Œ€์ฒด ์ด๊ฒŒ ๋ญ”๊ฐ€ ์‹ถ์—ˆ๋‹ค.


์›๋ž˜ Order ๊ด€๋ จ ๋ถ€๋ถ„์€ ์ „๋ถ€ ๋‚ด๊ฐ€ ๊ฑด๋“œ๋ฆฌ๋‹ค๊ฐ€, ํ”„๋ก ํŠธ์—์„œ item์ชฝ์„ ๊ธ‰ํ•˜๊ฒŒ ์†๋ด๋‹ฌ๋ผ๊ณ  ํ•ด์„œ
ํ•˜๋Š” ๋„์ค‘์— Order์— ๊ธฐ๋ณธ ํ‚ค๊ฐ€ ์•„๋‹Œ ์ฃผ๋ฌธ๋ฒˆํ˜ธ๊ฐ€ ๋ณ„๋„๋กœ ํ•„์š”ํ•  ๊ฒƒ ๊ฐ™๋‹ค๊ณ  ํ–ˆ๋‹ค
item์ด ์ƒ๊ฐ๋ณด๋‹ค ์˜ค๋ž˜๊ฑธ๋ ค์„œ ๋‹ค๋ฅธ ํŒ€์›์—๊ฒŒ ์–‘ํ•ด๋ฅผ ๊ตฌํ–ˆ๊ณ 
์ฃผ๋ฌธ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑ ํ›„์— Post ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด ์„œ๋น„์Šค์ธต์—์„œ ์ฝ”๋“œ ์ƒ์„ฑ ํ›„ set ํ•ด์ฃผ๊ธฐ๋กœ ํ–ˆ๋Š”๋ฐ
์ฝ”๋“œ๋Š” ์ž˜ ๋งŒ๋“ค์–ด์กŒ๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ post ์š”์ฒญ์„ ์—ฌ๋Ÿฌ ๋ฒˆ ํ•˜๋ฉด 500 ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๊ณ  ํ•ด์„œ
์ „์—๋Š” ๊ทธ๋Ÿฐ์ ์ด ์—†์—ˆ๋Š”๋ฐ ํ•˜๊ณ  ์ด์ œ ๋‹ค์‹œ Order ์ชฝ refactoring ํ›„ test ํ•ด๋ณด๋‹ˆ NonUniqueResultException์ด ๋ฐœ์ƒํ–ˆ๋‹ค



Postman์œผ๋กœ ์—ฐ์†ํ•ด์„œ ๋‘ ๋ฒˆ์˜ POST ์š”์ฒญ์„ ๋ณด๋ƒˆ๋Š”๋ฐ, ์ž๊พธ ์—๋Ÿฌ๊ฐ€ ํ„ฐ์ง€๊ธธ๋ž˜
ํฌ๊ฒŒ ๋‹ฌ๋ผ์ง„ ์ ์ด ์ฃผ๋ฌธ๋ฒˆํ˜ธ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ถ€๋ถ„์ด๋ผ์„œ ์ค‘๋ณต์ด ์™œ ๋ฐœ์ƒํ•˜์ง€ ํ•˜๊ณ  ์ฃผ๋ฌธ๋ฒˆํ˜ธ ์ƒ์„ฑํ•˜๋Š” ๋ถ€๋ถ„์„ ์ฃผ์„ ์ฒ˜๋ฆฌํ•ด๋ณด๋‹ˆ๊นŒ ์˜ˆ์™ธ๊ฐ€ ์•ˆ ํ„ฐ์กŒ๋‹ค.
์ด๊ฑธ ๋ณด๊ณ  ๋ฌธ์ œ๋Š” ํ™•์‹คํžˆ ์ฃผ๋ฌธ๋ฒˆํ˜ธ ์ƒ์„ฑ ๋ถ€๋ถ„์— ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ฒŒ ๋๋‹ค.
?

๋ฌธ์ œ์˜ ์›์ธ

์ญ‰ ์ฝ์–ด๋ณด๋‹ˆ findTopByOrderCdStartingWithOrderByOrderCdDesc(date) ์ด ์ฟผ๋ฆฌ๊ฐ€ ์›๋ž˜ ํ•˜๋‚˜์˜ ๊ฒฐ๊ณผ๋งŒ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋Š”๋ฐ, ๋‘ ๊ฐœ ์ด์ƒ์˜ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ˜ํ™˜๋๋‹ค๋Š” ๊ฒƒ ๊ฐ™์•˜๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// ์ฃผ๋ฌธ ์ฝ”๋“œ ์ƒ์„ฑ ๋ฉ”์„œ๋“œ
private String createOrderCd() {
    // ํ˜„์žฌ ๋‚ ์งœ๋ฅผ "yyMMMdd" ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ (MMM์€ ์›”์˜ ์˜์–ด ์•ฝ์ž)
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyMMMdd", Locale.ENGLISH);
    String date = LocalDate.now().format(formatter).toUpperCase();

    // ํ˜„์žฌ ๋‚ ์งœ์— ํ•ด๋‹นํ•˜๋Š” ๋งˆ์ง€๋ง‰ ์ฃผ๋ฌธ ์ฝ”๋“œ๋ฅผ DB์—์„œ ์กฐํšŒ
    Optional<String> lastOrderCdOptional = orderHeadersRepository.findTopByOrderCdStartingWithOrderByOrderCdDesc(date);

    // ๋งˆ์ง€๋ง‰ ์ฃผ๋ฌธ ์ฝ”๋“œ๊ฐ€ ์—†์œผ๋ฉด 00001๋ถ€ํ„ฐ ์‹œ์ž‘
    int newOrderNumber = 1;

    if (lastOrderCdOptional.isPresent()) {
        String lastOrderCd = lastOrderCdOptional.get();
        // ๋งˆ์ง€๋ง‰ ์ฃผ๋ฌธ ์ฝ”๋“œ์—์„œ ๋ฒˆํ˜ธ ๋ถ€๋ถ„ ์ถ”์ถœ (์˜ˆ: "24DEC1100001" -> 00001 ์ถ”์ถœ)
        String lastOrderNumberStr = lastOrderCd.substring(7); // ๋‚ ์งœ(6์ž๋ฆฌ) ์ดํ›„ ์ˆซ์ž(5์ž๋ฆฌ) ๋ถ€๋ถ„ ์ถ”์ถœ
        int lastOrderNumber = Integer.parseInt(lastOrderNumberStr);

        // ์ƒˆ๋กœ์šด ์ฃผ๋ฌธ ๋ฒˆํ˜ธ๋Š” ๋งˆ์ง€๋ง‰ ๋ฒˆํ˜ธ + 1
        newOrderNumber = lastOrderNumber + 1;
    }

    // ์ƒˆ๋กœ์šด ์ฃผ๋ฌธ ์ฝ”๋“œ ์ƒ์„ฑ (์˜ˆ: 24DEC1100002)
    String newOrderCd = String.format("%s%05d", date, newOrderNumber);

    return newOrderCd;
}

์ฃผ๋ฌธ๋ฒˆํ˜ธ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ, ๊ฐ™์€ ๋‚ ์— ์—ฌ๋Ÿฌ ์ฃผ๋ฌธ์ด ๋“ค์–ด์˜ค๋ฉด ๊ทธ๋‚  ๋‚ ์งœ๋กœ ์‹œ์ž‘ํ•˜๋Š” ์ฃผ๋ฌธ๋ฒˆํ˜ธ๋“ค์ด DB์— ์—ฌ๋Ÿฌ ๊ฐœ ์Œ“์ด๊ฒŒ ๋œ๋‹ค. ๊ทผ๋ฐ ์—ฌ๊ธฐ์„œ findTopByOrderCdStartingWithOrderByOrderCdDesc(date)๊ฐ€ ๊ทธ ๋‚ ์งœ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฐ€์žฅ ์ตœ๊ทผ์˜ ์ฃผ๋ฌธ๋ฒˆํ˜ธ๋ฅผ ์ฐพ๋Š” ์ฟผ๋ฆฌ๋‹ค ๋ณด๋‹ˆ, ๊ฐ™์€ ๋‚ ์งœ์— ์ค‘๋ณต๋œ ๊ฒฐ๊ณผ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์ด์—ˆ๋‹ค.

๊ฒฐ๊ตญ ์ฟผ๋ฆฌ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ๊ทธ๊ฑธ ํ•˜๋‚˜๋กœ ๋ฌถ์ง€ ๋ชปํ•ด์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒƒ ๊ฐ™๋‹ค.

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

  1. ์ฃผ๋ฌธ๋ฒˆํ˜ธ ์ƒ์„ฑํ•  ๋•Œ ์ค‘๋ณต์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์ฟผ๋ฆฌ๋ถ€ํ„ฐ ์ˆ˜์ • ํ•„์š”
    • findTopByOrderCdStartingWithOrderByOrderCdDesc() ์ด ๋ถ€๋ถ„์—์„œ ๊ฐ€์žฅ ์ตœ๊ทผ ํ•˜๋‚˜์˜ ์ฃผ๋ฌธ๋ฒˆํ˜ธ๋งŒ ์ •ํ™•ํ•˜๊ฒŒ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์ฟผ๋ฆฌ ์กฐ๊ฑด์„ ์ˆ˜์ •
  2. ๋™์‹œ์„ฑ ๋ฌธ์ œ๋„ ๊ณ ๋ ค
    • ๋‚ด๊ฐ€ ์—ฐ์†์œผ๋กœ ๋‘ ๋ฒˆ POST ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ์ƒํ™ฉ์ด๋ผ๋ฉด ๋™์‹œ์— ์—ฌ๋Ÿฌ ์ฃผ๋ฌธ์ด ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ฃผ๋ฌธ๋ฒˆํ˜ธ ์ƒ์„ฑ ๋กœ์ง์— ๋™๊ธฐํ™”๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜,
    • DB์—์„œ ์ˆœ์ฐจ์ ์œผ๋กœ ์ฃผ๋ฌธ๋ฒˆํ˜ธ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ํ•„์š”
      • ์˜ˆ๋ฅผ ๋“ค์–ด, synchronized ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ฃผ๋ฌธ๋ฒˆํ˜ธ ์ƒ์„ฑํ•  ๋•Œ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ฑฐ๋‚˜,
      • DB์—์„œ ๊ณ ์œ ํ•œ ์ฃผ๋ฌธ๋ฒˆํ˜ธ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”์„ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด์„œ ๊ทธ๊ฑธ ์ฐธ์กฐํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค.


    1
    2
    3
    
        
         private synchronized String createOrderCd() {
         }
    
    • ์ด๋ ‡๊ฒŒ synchronized๋ฅผ ๋ถ™์ด๋ฉด ํ•ด๋‹น ๋ฉ”์„œ๋“œ์— ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋™์‹œ์„ฑ์„ ๋ง‰์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.

    • Synchronized

      • ์ž๋ฐ”์—์„œ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ๋™์‹œ ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ํ‚ค์›Œ๋“œ
      • ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋‚˜ ๋ธ”๋ก์— ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•˜๋„๋ก ํ•ด์„œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€
  3. ๋‚ด๊ฐ€ ๊ฐœ์„ ํ•œ ๋ฐฉ๋ฒ•
    • ์œ„์˜ ๋ฐฉ๋ฒ•์„ ๊ณ ์ง‘ํ•˜๋ ค๊ณ  ํ•˜๋‹ˆ๊นŒ ์†”์งํžˆ ์ฃผ๋ฌธ๋ฒˆํ˜ธ ์ƒ์„ฑํ•˜๋Š”๋ฐ DB๋„ ์กฐํšŒํ•˜๋Š” ๋“ฑ๋“ฑ์˜ ๋น„์šฉ์ด ๋„ˆ๋ฌด ๋งŽ์ด ๋“ ๋‹ค๋Š” ์ƒ๊ฐ์ด๋“ค์–ด ๊ทธ๋ƒฅ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ๋‹ค.
    • ๋žœ๋ค ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์•˜๋”๋‹ˆ randonUUID๊ฐ€ ๊ฑฐ์˜ ์ค‘๋ณต์ด ์—†๋‹ค๊ณ  ํ•ด์„œ ์ด ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฒฐ์ •ํ–ˆ๊ณ 
    • ๊ธฐ์กด์˜ ์ฃผ๋ฌธ์ฝ”๋“œ ์ƒ์„ฑ ๋ฐฉ๋ฒ•์ฒ˜๋Ÿผ ํšŒ์‚ฌ์˜ ์ƒ์„ฑ๊ทœ์น™์„
    1
    2
    3
    4
    5
    6
    
             // ์ฃผ๋ฌธ ์ฝ”๋“œ ์ƒ์„ฑ ๋ฉ”์„œ๋“œ
         private String createOrderCd() {
             String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 12).toUpperCase();
    
             return "SHO" + uuid;
         }
    

    ๋‹จ์ˆœ ์ฃผ๋ฌธ์ฝ”๋“œ ์ƒ์„ฑ์ธ๋ฐ ์ฒ˜์Œ ๋ณด๋Š” ์˜ˆ์™ธ ๋ฐœ์ƒ ๋•Œ๋ฌธ์— ์‹œ๊ฐ„์ด ์‚ฌ๋ฅด๋ฅด๋ฅต ๋…น์•„๋ฒ„๋ ธ๋‹ค. ์ฃผ๋ฌธ์ด ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ ๋ฒŒ์จ ์ฝ”๋“œ ํ•˜๋‚˜ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์—์„œ ๋งŒ๋‚˜์„œ ๋‹นํ™ฉ์Šค๋Ÿฝ๋‹ค..


Project ์นดํ…Œ๊ณ ๋ฆฌ ๋‚ด ๋‹ค๋ฅธ ๊ธ€ ๋ณด๋Ÿฌ๊ฐ€๊ธฐ

Leave a comment