CH05 Spring Data JPA

JpaRepository.save()

save() ๋Š” ๋‹จ์ˆœํžˆ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ €์žฅํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹˜. ๊ฒฝ์šฐ์— ๋”ฐ๋ผ persist ๋˜๋Š” merge ๋กœ ๋™์ž‘ํ•œ๋‹ค.

  • Transient ์ƒํƒœ์˜ ๊ฐ์ฒด๋ผ๋ฉด EntityManager.persist()

  • Detached ์ƒํƒœ์˜ ๊ฐ์ฒด๋ผ๋ฉด EntityManager.merge()

persist

Persist() ๋ฉ”์†Œ๋“œ์— ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ธด(save ๋Œ€์ƒ) ๊ทธ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ Persistent ์ƒํƒœ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค. save() ๊ฒฐ๊ณผ๋กœ ๋ฐ˜ํ™˜๋ฐ›์€ saved entity ๊ฐ€ ๊ณง ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ธด ๊ทธ save ๋Œ€์ƒ๊ณผ ๊ฐ™๋‹ค.

@DataJpaTest
public class PostRepositoryTest {

    @Autowired
    PostRepository postRepository;

    @PersistenceContext
    EntityManager entityManager;

    @Test
    void saveTest() {
        Post post = new Post();
        post.setName("name_1");
        post.setDescription("description_1");
        Post savedPost = postRepository.save(post);

        Assertions.assertThat(entityManager.contains(post)).isTrue();
        Assertions.assertThat(entityManager.contains(savedPost)).isTrue();
        Assertions.assertThat(post).isEqualTo(savedPost);
    }

}

merge

์ฃผ์„ ํ‘œ์‹œํ•œ ๊ฒƒ๋“ค์„ ์ž˜ ๊ธฐ์–ตํ•˜์ž. update ์‹œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ธด entity๋Š” ์˜์†ํ™”๋˜์ง€ ์•Š๊ณ  ๊ทธ๊ฒƒ์˜ ๋ณต์‚ฌ๋ณธ์ด ์˜์†ํ™” ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์˜์†ํ™”๋œ ๊ฐ์ฒด๊ฐ€ return ๋œ๋‹ค.

์ด ํฌ์ธํŠธ๊ฐ€ ์ฃผ๋Š” ์ค‘์š”ํ•œ ์‹œ์‚ฌ์ ์€ update ๋กœ์ง ์ฒ˜๋ฆฌ ์ดํ›„ ํ›„์† ์ž‘์—…์„ ํ•ด์•ผํ•  ๊ฒฝ์šฐ ๋ฐ˜๋“œ์‹œ return ๋œ ๊ทธ ๊ฐ’์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๊ทธ ๊ฐ์ฒด๊ฐ€ persistent ๋œ ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ฐ˜๋Œ€๋กœ ๋งํ•˜๋ฉด save() ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ธด ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์™œ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋˜๋ƒ? managed ๊ฐ์ฒด๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ฆ‰, persistent ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ƒํƒœ๊ฐ€ ์ถ”์ ์ด ๋˜์ง€ ์•Š์•„์„œ dirty check ๋“ฑ JPA์˜ ์ด์ ์„ ๋ˆ„๋ฆฌ์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

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

์•„๋ž˜๋Š” ๊ฐ•์˜ ๋…ธํŠธ ๊ทธ๋Œ€๋กœ ๋ฐœ์ทŒ.

  • ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜ ํ”„๋กœ์ ์…˜

    • Nested ํ”„๋กœ์ ์…˜ ๊ฐ€๋Šฅ.

    • Closed ํ”„๋กœ์ ์…˜

      • ์ฟผ๋ฆฌ๋ฅผ ์ตœ์ ํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฐ€์ ธ์˜ค๋ ค๋Š” ์• ํŠธ๋ฆฌ๋ทฐํŠธ๊ฐ€ ๋ญ”์ง€ ์•Œ๊ณ  ์žˆ์œผ๋‹ˆ๊นŒ.

      • Java 8์˜ ๋””ํดํŠธ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์—ฐ์‚ฐ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

    • Open ํ”„๋กœ์ ์…˜

      • @Value(SpEL)์„ ์‚ฌ์šฉํ•ด์„œ ์—ฐ์‚ฐ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์Šคํ”„๋ง ๋นˆ์˜ ๋ฉ”์†Œ๋“œ๋„ ํ˜ธ์ถœ ๊ฐ€๋Šฅ. -์ฟผ๋ฆฌ ์ตœ์ ํ™”๋ฅผ ํ•  ์ˆ˜ ์—†๋‹ค. SpEL์„ ์—”ํ‹ฐํ‹ฐ ๋Œ€์ƒ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์—.

  • ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ํ”„๋กœ์ ์…˜

    • DTO

    • ๋กฌ๋ณต @Value๋กœ ์ฝ”๋“œ ์ค„์ผ ์ˆ˜ ์žˆ์Œ

Specification

query DSL ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ query ๋ฅผ ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค. ์•„๋ž˜๋Š” JPA ๊ณต์‹ ๋ฌธ์„œ์—์„œ Specification ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•œ ๊ธ€ ์ผ๋ถ€๋‹ค.

JPA 2 introduces a criteria API that you can use to build queries programmatically. By writing a criteria, you define the where clause of a query for a domain class. Taking another step back, these criteria can be regarded as a predicate over the entity that is described by the JPA criteria API constraints.

์‚ฌ์šฉ ๋ฐฉ๋ฒ•์€ ๊ณต์‹๋ฌธ์„œ์—๋„ ๋‚˜์™€์žˆ์ง€๋งŒ ๊ฐ„๋‹จํ•˜๋‹ค. repository ์—์„œ JpaSpecificationExecutor ๋ฅผ ์ƒ์† ๋ฐ›๊ณ  findAll() ์— ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ Specification ์„ ๋„˜๊ฒจ์ค€๋‹ค. pageable ๋„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ฒจ์ฃผ๋ฉด ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

์œ ์šฉํ•˜์ง€๋งŒ ํƒ€์ž… ์„ธ์ดํ”„ํ•˜์ง€ ์•Š์•„์„œ ๊ทธ๋ƒฅ queryDsl ์“ฐ๋Š”๊ฒŒ ๋งˆ์Œ ํŽธํ•˜๋‹ค.

๋งŒ์•ฝ ์—ฌ๊ธฐ์„œ ์•„๋ž˜์™€ ๊ฐ™์ด DESCRIPTION ์— null ์„ ๋„ฃ์„ ๊ฒฝ์šฐ ์ฟผ๋ฆฌ๊ฐ€ ์˜๋„ํ•œ๋Œ€๋กœ ๋‹ฌ๋ผ์ง„๋‹ค.

Auditing

ํŠน๋ณ„ํ•œ ๋‚ด์šฉ์€ ์—†์–ด์„œ ๊ฐ•์˜์ž๋ฃŒ๋งŒ ์ฒจ๋ถ€ํ•œ๋‹ค.

  • ๋ฉ”์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์œ„์— @EnableJpaAuditing ์ถ”๊ฐ€ (์Šคํ”„๋ง๋ถ€ํŠธ๊ฐ€ ์ž๋™์„ค์ • ํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค)

  • ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค ์œ„์— @EntityListeners(AuditingEntityListener.class) ์ถ”๊ฐ€

Last updated