๐Ÿ“Œ [MarketBridge] 03. ๊ฐœ๋ฐœ์ผ์ง€ - IDENTITY ์ „๋žต์— ๋”ฐ๋ฅธ ํ…Œ์ŠคํŠธ ์‹คํŒจ

๋ชจ๊น…ยท2024๋…„ 1์›” 30์ผ
0

๊ฐœ๋ฐœ์ผ์ง€ - MarketBridge

๋ชฉ๋ก ๋ณด๊ธฐ
3/8
post-thumbnail

๐Ÿ“– IDENTITY ์ „๋žต์— ๋”ฐ๋ฅธ ํ…Œ์ŠคํŠธ ์‹คํŒจ

@Transactional
@SpringBootTest
@ActiveProfiles("test")
class ProductListResponseDtoTest {

    @Autowired ProductRepository productRepository;

    @Test
    @DisplayName("์ฃผ๋ฌธ ์ƒ์„ธ๊ฐ€ ์ฃผ์–ด์กŒ์„ ๋•Œ ProductListResponseDto ๋ณ€ํ™˜")
    public void ofWithOrderDetail() {
        Product product = Product.builder()
                .price(1000L)
                .name("๋นต๋นต์ด")
                .productNo("123")
                .build();
        productRepository.save(product);

        OrderDetail orderDetail = OrderDetail.builder()
                .product(product)
                .price(product.getPrice())
                .quantity(2L)
                .build();

        // when
        ProductListResponseDto result = ProductListResponseDto.of(orderDetail);

        // then
        assertThat(result).extracting("productId", "productNo", "name", "price", "quantity")
                .contains(1L, "123", "๋นต๋นต์ด", 1000L, 2L);
    }


    @Test
    @DisplayName("์ƒํ’ˆ๊ณผ ์ˆ˜๋Ÿ‰์ด ์ฃผ์–ด์กŒ์„ ๋•Œ ProductListResponseDto ๋ณ€ํ™˜")
    public void ofWithProductAndQuantity() {
        Long quantity = 2L;

        Product product = Product.builder()
                .price(1000L)
                .name("๋นต๋นต์ด")
                .productNo("123")
                .build();
        productRepository.save(product);

        // when
        ProductListResponseDto result = ProductListResponseDto.of(product, quantity);

        // then
        assertThat(result).extracting("productId", "productNo", "name", "price", "quantity")
                .contains(1L, "123", "๋นต๋นต์ด", 1000L, 2L);

    }

@Transactional๋ฅผ ํ†ตํ•ด ๊ฐ ํ…Œ์ŠคํŠธ๊ฐ€ ๋กค๋ฐฑ๋˜์–ด productId๊ฐ€ ๋ชจ๋‘ 1L ๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ–ˆ๋‹ค.

๊ธฐ๋Œ€์™€ ๋‹ฌ๋ฆฌ ์‹คํŒจ๋ฅผ ํ•˜์˜€๋‹ค. ์ฒซ๋ฒˆ์งธ ํ…Œ์ŠคํŠธ(ofWithOrderDetail)์˜ productId์˜ ๊ฐ’์ด 2L ๋˜์—ˆ๋‹ค. ๋ญ์•ผ.. ์™œ..?

์ฒ˜์Œ์—๋Š” ๋กค๋ฐฑ์ด ์•ˆ๋๋‚˜? ์ƒ๊ฐํ–ˆ์ง€๋งŒ

Hibernate: 
    insert 
    into
        product
        (category_id, created_at, deleted_at, discount_rate, is_own, is_subs, name, price, product_no, stock, thumb_img, updated_at, product_id) 
    values
        (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, default)
2024-01-29T22:28:07.219+09:00  INFO 3636 --- [           main] p6spy                                    : #1706534887219 | took 4ms | statement | connection 3| url jdbc:h2:mem:~/Marketbridge
insert into product (category_id,created_at,deleted_at,discount_rate,is_own,is_subs,name,price,product_no,stock,thumb_img,updated_at,product_id) values (?,?,?,?,?,?,?,?,?,?,?,?,default)
insert into product (category_id,created_at,deleted_at,discount_rate,is_own,is_subs,name,price,product_no,stock,thumb_img,updated_at,product_id) values (NULL,NULL,NULL,NULL,NULL,NULL,'๋นต๋นต์ด',1000,'123',NULL,NULL,NULL,default);
2024-01-29T22:28:07.299+09:00  INFO 3636 --- [           main] p6spy                                    : #1706534887299 | took 0ms | rollback | connection 3| url jdbc:h2:mem:~/Marketbridge

;
Hibernate: 
    insert 
    into
        product
        (category_id, created_at, deleted_at, discount_rate, is_own, is_subs, name, price, product_no, stock, thumb_img, updated_at, product_id) 
    values
        (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, default)
2024-01-29T22:28:07.309+09:00  INFO 3636 --- [           main] p6spy                                    : #1706534887309 | took 0ms | statement | connection 4| url jdbc:h2:mem:~/Marketbridge
insert into product (category_id,created_at,deleted_at,discount_rate,is_own,is_subs,name,price,product_no,stock,thumb_img,updated_at,product_id) values (?,?,?,?,?,?,?,?,?,?,?,?,default)
insert into product (category_id,created_at,deleted_at,discount_rate,is_own,is_subs,name,price,product_no,stock,thumb_img,updated_at,product_id) values (NULL,NULL,NULL,NULL,NULL,NULL,'๋นต๋นต์ด',1000,'123',NULL,NULL,NULL,default);
2024-01-29T22:28:07.317+09:00  INFO 3636 --- [           main] p6spy                                    : #1706534887317 | took 0ms | rollback | connection 4| url jdbc:h2:mem:~/Marketbridge

;

insert๋ฌธ์„ ๋ณด๋ฉด rollback์ด ๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ด๋ฆฌ ์ €๋ฆฌ ์‚ฝ์งˆํ•˜๋˜ ์ค‘ ์—”ํ‹ฐํ‹ฐ์˜ ID๊ฐ€ Identity์ „๋žต์œผ๋กœ ๋งŒ๋“ค์–ด์ง€๊ณ  ์žˆ์—ˆ๋Š”๋ฐ ์ด๊ฒƒ์ด ๋ฌธ์ œ๊ฐ€ ๋˜๊ณ  ์žˆ์—ˆ๋‹ค...

โœ๏ธ IDENTITY ์ „๋žต

์ž ์‹œ IDENTITY ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.

IDENTITY ์ „๋žต์€ ๋ถ„๋ช…ํ•œ ๋‹จ์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๊ฐ’์„ ์ €์žฅํ•˜๊ณ  ๋‚˜์„œ์•ผ ๊ธฐ๋ณธ ํ‚ค ๊ฐ’์„ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค.
์ด๊ฒƒ์ด ๋ฌด์Šจ ๋ง์ด๋ƒ? ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— 1์ฐจ ์บ์‹œ(์˜์†ํ™”)๋ฅผ ํ•  ๋•Œ ์—”ํ‹ฐํ‹ฐ๋Š” Id๋ฅผ ๋ฌด~์กฐ๊ฑด ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•˜๋Š”๋ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊ฐ’์„ ์ œ๊ณตํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ๋‹จ์ˆœํžˆ ํ‚ค๋ฅผ ์–ป๋Š” ๊ณผ์ •์ธ๋ฐ๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋„คํŠธ์›Œํฌ๋ฅผ ํ•œ ๋ฒˆ ํƒ€์•ผํ•˜๋Š” ๋ถˆ์ƒ์‚ฌ๊ฐ€ ์ผ์–ด๋‚œ๋‹ค.

์ •๋ฆฌํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๊ฐ€์„œ Id๋ฅผ ๋ฐ›์•„์˜จ ํ›„ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์บ์‹œ๊ฐ€ ๋œ๋‹ค.

๋งŒ์•ฝ ์ด๊ฒŒ ์‹ซ๋‹ค๋ฉด? SEQUENCE ์ „๋žต์„ ํ•œ ๋ฒˆ ์•Œ์•„๋ณด๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค!
์ตœ์ ํ™” ๋ถ€๋ถ„์—์„œ ์ด๋“์„ ์–ป์„ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

โ—IDENTITY ์ „๋žต ์ฃผ์˜์ 

IDENTITY ์ „๋žต์— ๋Œ€ํ•ด ๋Œ€์ถฉ ์•Œ์•„๋ณด์•˜๋Š”๋ฐ ๋„๋Œ€์ฒด ์ด๊ฒŒ ํ…Œ์ŠคํŠธ์—์„œ ์–ด๋–ค ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚จ๊ฑธ๊นŒ?

IDENTITY ์ „๋žต์„ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•  ์ ์ด ์กด์žฌํ•œ๋‹ค.
AUTO INCREMENT ๋Š” Transaction ์„ ์‚ฌ์šฉํ•ด๋„ rollback ๋˜์ง€ ์•Š๋Š”๋‹ค.
์ด๊ฒŒ ๋ฌด์Šจ๋ง์ด๋ƒ๋ฉด, Insert ์ฟผ๋ฆฌ๋ฅผ ์‹คํŒจํ•ด๋„ Table ์˜ AUTO INCREMENT ์ปฌ๋Ÿผ์˜ ๊ฐ’์€ 1์ด ์ฆ๊ฐ€๋œ๋‹ค.

์œ„์— ํ…Œ์ŠคํŠธ๋ฅผ ๋‹ค์‹œ ์˜ˆ๋กœ ๋“ค์–ด๋ณด๋ฉด IDENTITY ์ „๋žต์€ rollback์ด ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋‘๋ฒˆ์งธ๋กœ ์ง„ํ–‰๋œ ํ…Œ์ŠคํŠธ์˜ productId๊ฐ€ 2๊ฐ€ ๋œ ๊ฒƒ์ด๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•ด์•ผ ํ• ๊นŒ?
AUTO INCREMENT ๊ฐ’์„ ์‹ ๋ขฐํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค. ๋งŒ์•ฝ AUTO INCREMENT ๊ฐ’์„ ์ค‘์š”ํ•˜๊ฒŒ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, innodb_autoinc_lock_mode์„ ์ž˜ ์•Œ์•„์•ผํ•œ๋‹ค.

innodb_autoinc_lock_mode์— ๋Œ€ํ•ด์„œ๋Š” ๋”ฐ๋กœ ์•Œ์•„๋ณด์ง€ ์•Š๊ฒ ๋‹ค. ํ•„์š”ํ•˜๋‹ค๋ฉด ๊ฒ€์ƒ‰ํ•ด์„œ ๋ณด๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•˜๊ฒ ๋‹น

๐Ÿ•ถ๏ธ ๊ฒฐ๋ก 

์ง€๊ธˆ ํ”„๋กœ์ ํŠธ๋Š” my-sql์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— IDENTITY์ „๋žต์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์—†์„๊ฒƒ์œผ๋กœ ์ƒ๊ฐ๋œ๋‹ค.
๊ทธ๋ ‡๋‹ค๊ณ  innodb_autoinc_lock_mode๋ฅผ ๊ณต๋ถ€ํ•ด์„œ ์ ์šฉํ•˜๊ธฐ์—” db๋ฌด๋‡Œํ•œ์œผ๋กœ์„œ๋Š” ์Šคํ”„๋ฆฐํŠธ๋ฅผ ํ•ด์•ผํ•˜๋Š” ์ง€๊ธˆ ์‹œ๊ธฐ์— ์–ด๋ ค์›Œ๋ณด์ธ๋‹ค. (์•„๋ฌด๊ฒƒ๋„ ๋ชจ๋ฅด๊ธฐ์— ์‹œ๊ฐ„ ์˜ˆ์ธก์ด ์•ˆ๋˜๊ธฐ ๋•Œ๋ฌธ,,,ใ… ใ… )

์ง€๊ธˆ ๋‹จ์ˆœํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋Š”๋ฐ Id๋ฅผ ์œ„ํ•ด์„œ ์Šคํ”„๋ง์„ ๋„์šฐ๋Š” ๊ฒƒ๊ณผ db๋ฅผ ๊ณต๋ถ€ํ•˜๋Š” ๊ฒƒ ๋‘๊ฐœ ๋‹ค ๋ถ€๋‹ด์Šค๋Ÿฝ๊ธฐ ๋•Œ๋ฌธ์— Reflection์„ ํ†ตํ•ด ์Šคํ”„๋ง ์—†์ด ๋‹จ์œ„ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ ํ•  ์˜ˆ์ •์ด๋‹ค. Id๋งŒ ๋„ฃ์–ด์ฃผ๋ฉด ๋˜๋‹ˆ๊น..! ์ด ๋ฐฉ๋ฒ•์ด ์ง€๊ธˆ ์ƒํ™ฉ์—์„œ ์ข‹์€ ํŒ๋‹จ์ด๋ผ๊ณ  ์ƒ๊ฐ๋œ๋‹ค.

โœ๏ธ ์ฝ”๋“œ ์ˆ˜์ •

class ProductListResponseDtoTest {


    @Test
    @DisplayName("์ฃผ๋ฌธ ์ƒ์„ธ๊ฐ€ ์ฃผ์–ด์กŒ์„ ๋•Œ ProductListResponseDto ๋ณ€ํ™˜")
    public void ofWithOrderDetail() {
        Product product = Product.builder()
                .price(1000L)
                .name("๋นต๋นต์ด")
                .productNo("123")
                .build();
        ReflectionTestUtils.setField(product, "id", 1L, Long.class);
        OrderDetail orderDetail = OrderDetail.builder()
                .product(product)
                .price(product.getPrice())
                .quantity(2L)
                .build();

        // when
        ProductListResponseDto result = ProductListResponseDto.of(orderDetail);

        // then
        assertThat(result).extracting("productId", "productNo", "name", "price", "quantity")
                .contains(1L, "123", "๋นต๋นต์ด", 1000L, 2L);
    }


    @Test
    @DisplayName("์ƒํ’ˆ๊ณผ ์ˆ˜๋Ÿ‰์ด ์ฃผ์–ด์กŒ์„ ๋•Œ ProductListResponseDto ๋ณ€ํ™˜")
    public void ofWithProductAndQuantity() {
        Long quantity = 2L;

        Product product = Product.builder()
                .price(1000L)
                .name("๋นต๋นต์ด")
                .productNo("123")
                .build();
        ReflectionTestUtils.setField(product, "id", 1L, Long.class);

        // when
        ProductListResponseDto result = ProductListResponseDto.of(product, quantity);

        // then
        assertThat(result).extracting("productId", "productNo", "name", "price", "quantity")
                .contains(1L, "123", "๋นต๋นต์ด", 1000L, 2L);

    }

}

ReflectionTestUtils๋ฅผ ํ†ตํ•ด ๊ฐ’์„ ์…‹ํŒ…ํ•ด์ฃผ์—ˆ๋‹ค.
์Šคํ”„๋ง ์—†์ด ๋‹จ์œ„ํ…Œ์ŠคํŠธ๋กœ ์ง„ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ›จ์”ฌ ๋น ๋ฅธ ์†๋„๋ฅผ ๋ณด์ธ๋‹ค!!

profile
๋ฉˆ์ถ”์ง€ ์•Š๊ธฐ

0๊ฐœ์˜ ๋Œ“๊ธ€