๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Spring/JPA

JPA์—์„œ Lombok ์‚ฌ์šฉ์‹œ ์ฃผ์˜ํ•  ์ 

by ํ‘์‹œ๋ฐ” 2023. 12. 30.

๐Ÿคฃ  ๋ฐฐ๊ฒฝ

ํ”„๋กœ์ ํŠธ๋ฅผ ๋งˆ์น˜๊ณ  ๋‚˜๋ฉด ํ•ญ์ƒ ์ฝ”๋“œ ์ธ์ŠคํŽ™์…˜ ๊ณผ์ •์„ ํ†ตํ•ด ํ”„๋กœ๊ทธ๋žจ์— ๋Œ€ํ•œ ์ทจ์•ฝ์ ์ด๋‚˜ ์žฅ์• ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ์„ ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ,  ๊ฐ„ํ˜น equals์™€ hashcode๊ฐ€ ๊ตฌํ˜„๋˜์ง€ ์•Š์€ ์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•ด ๊ฒฝ๊ณ ๋กœ ์ง€์ ์„ ๋‹นํ•˜๊ฒŒ ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ข…์ข… ์žˆ๋‹ค.

 

์ฒ˜์Œ์—๋Š” Lombok์—์„œ ์ œ๊ณตํ•˜๋Š” @EqualsAndHashCode๋ฅผ ์จ์„œ ๊ฐ„ํŽธํ•˜๊ฒŒ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ํ–ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋‚˜์ค‘์— ํ”„๋กœ๊ทธ๋žจ ์‚ฌ์šฉ ์ค‘์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด์„œ Lombok ์‚ฌ์šฉ์ด ๋ฌธ์ œ๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๊ณ , ๋‹ค๋ฅธ ๋ฌธ์ œ๋Š” ์—†์„์ง€ JPA์— Lombok์„ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•  ์ ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒŒ ๋˜์—ˆ๋‹ค.

๋ฌธ์ œ์  1. HashMap, HashSet ์‚ฌ์šฉ์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

- Shiba ์—”ํ‹ฐํ‹ฐ

@Entity
@Table(name = "tb_shiba_holic")
@EqualsAndHashCode
public final class Shiba {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "seq", nullable = false)
    private Long seq;

    private String name;
}

- ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

    @Test
    @DisplayName("๊ฐ™์€ ๊ฐ์ฒด์ธ์ง€ ํ™•์ธํ•œ๋‹ค.")
    void sameValue() {
        Shiba shiba = new Shiba();
        Set<Shiba> shibaSet = new HashSet<>();

        shibaSet.add(shiba);
        shibaRepository.save(shiba);

        assertThat(shibaSet.contains(shiba)).isTrue();
    }

 

๋™์ผํ•œ ๊ฐ์ฒด์ด๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•˜๋Š” ์œ„ ํ…Œ์ŠคํŠธ๋Š” ์‹ค์ œ๋กœ ์‹คํ–‰ํ•ด ๋ณด๋ฉด ์‹คํŒจํ•œ๋‹ค.

 

 

JPA์— ์ €์žฅํ•˜๋Š” ๊ณผ์ •์—์„œ ID๊ฐ€ ์ƒ์„ฑ๋˜๋ฉด์„œ Hashcode๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด HashSet/HashMap ์ €์žฅ๋œ ๊ฐ์ฒด๋Š” ๋ณ„๋„์˜ ๊ฒƒ์œผ๋กœ ์ธ์ง€ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

๋”ฐ๋ผ์„œ @EqualsAndHashCode๋Š” ์ง์ ‘ ๊ตฌํ˜„ํ•ด์„œ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ of ์˜ต์…˜ exclude ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด์„œ ํŠน์ • ํ•„๋“œ๋งŒ ํ•ด๋‹น๋˜๋„๋ก ์ •์˜ํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค.

(+ @Data์—๋„ @EqualsAndHashCode๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ์ฃผ์˜ํ•˜์ž)

๋ฌธ์ œ์  2. Lazy ์—ฐ๊ด€ ๊ด€๊ณ„ ํ•„๋“œ๊ฐ€ ์ž๋™์œผ๋กœ ํ˜ธ์ถœ๋œ๋‹ค.

@EqualsAndHashCode, @ToString์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์—”ํ‹ฐํ‹ฐ์— ์„ ์–ธํ•œ ๋ชจ๋“  ํ•„๋“œ๊ฐ€ ํฌํ•จ๋œ๋‹ค.

 

๋”ฐ๋ผ์„œ ์„œ๋น„์Šค ์ฝ”๋“œ ๋‚ด์— ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ณผ์ •์—์„œ toString(), equals(), hashCode() ๋“ฑ์ด ํ˜ธ์ถœ๋˜๋Š” ๊ฒฝ์šฐ Lazy ํ•„๋“œ๊ฐ€ ์ž๋™์œผ๋กœ ํ˜ธ์ถœ๋  ์ˆ˜ ์žˆ๋‹ค.

 

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

- Shiba ์—”ํ‹ฐํ‹ฐ

@Entity
@Table(name = "tb_shiba_holic")
@ToString
@Getter
public final class Shiba {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "seq", nullable = false)
    private Long seq;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "shiba")
    private List<Item> itemList = new ArrayList<>();
}

- ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

    @Test
    @DisplayName("toString()์„ ํ˜ธ์ถœํ•œ๋‹ค.")
    void callToString() {
        Shiba shiba = new Shiba();
        Shiba savedShiba = shibaRepository.save(shiba);

        Item item1 = Item.builder()
                .shiba(savedShiba)
                .build();
        itemRepository.save(item1);

        Item item2 = Item.builder()
                .shiba(savedShiba)
                .build();
        itemRepository.save(item2);

        // ์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ €๋ฅผ ์ดˆ๊ธฐํ™” ํ•œ๋‹ค.
        entityManager.flush();
        entityManager.clear();

        Shiba shibaEntity = shibaRepository.findById(savedShiba.getSeq()).get();
        System.out.println(shibaEntity);
    }

 

shibaEntity์˜ toString()์„ ํ˜ธ์ถœํ•œ๋‹ค.

 

 

๊ทธ ๊ฒฐ๊ณผ ์˜๋„ํ•˜์ง€ ์•Š์€ item ๋ชฉ๋ก์„ ์กฐํšŒํ•˜๋Š” select ์ฟผ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€๋กœ ๋‚˜๊ฐ€๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์–‘๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„์—์„œ ์„œ๋กœ @ToString์ด ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ์—๋Š”, ์„œ๋กœ๊ฐ€ ์„œ๋กœ๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜๋ฉด์„œ StackOverflowError ์˜ˆ์™ธ๊นŒ์ง€ ๋ฐœ์ƒํ•œ๋‹ค.

 

@ToString์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ์ง์ ‘ ๊ตฌํ˜„ํ•˜๊ฑฐ๋‚˜ exclude ์˜ต์…˜ ๋˜๋Š” onlyExplicitlyIncluded ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด์„œ Lazy ๊ด€๋ จ ํ•„๋“œ๋Š” ์ œ์™ธ์‹œ์ผœ์•ผ ํ•œ๋‹ค.

(+ @Data์—๋„ @ToString์ด ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ์ฃผ์˜ํ•˜์ž)

๋Œ“๊ธ€