Dev/JPA

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ(Entity LifeCycle)

OK-๊ฐ€์ž 2022. 3. 2. 17:29

๐Ÿ˜Ž ์˜์†์„ฑ์ปจํ…์ŠคํŠธ์—์„œ ๊ฐ€์žฅ ์ฃผ์ฒด๊ฐ€ ๋˜๋Š” ํด๋ž˜์Šค๋Š” ์—”ํ‹ฐํ‹ฐ๋ฉ”๋‹ˆ์ ธ๊ฐ์ฒด์ด๋‹ค. ์—”ํ‹ฐํ‹ฐ๋Š” ํ•˜๋‚˜์˜ ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— ์—”ํ‹ฐํ‹ฐ์™€ DB๋ ˆ์ฝ”๋“œ ์‚ฌ์ด์— ์–ด๋–ป๊ฒŒ ์—ฐ๊ฒฐํ•ด์ฃผ๊ณ , ์–ด๋–ป๊ฒŒ ๋ฐ˜์˜ํ•ด ์ฃผ๋Š”์ง€, ๋ชจ๋‘ ์—”ํ‹ฐํ‹ฐ๋ฉ”๋‹ˆ์ ธ์˜ ์—ญํ™œ์ด๋‹ค. ์˜์†์„ฑ์ปจํ…์ŠคํŠธ ๋‚ด์—์„œ ์—”ํ‹ฐํ‹ฐ๋งค๋‹ˆ์ ธ๊ฐ€ ์—”ํ‹ฐํ‹ฐ์˜ ์ƒํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ๋ณ€ํ™”์‹œํ‚ค๋Š”์ง€ ์•Œ์•„๋ณด์ž.

Entity ์ƒ์• ์ฃผ๊ธฐ ์•Œ์•„๋ณด๊ธฐ(Entity LifeCycle)

  • ์—”ํ‹ฐํ‹ฐ ๋ผ์ดํ”„์‚ฌ์ดํด ์ด๋ผ๊ณ  ํ•˜๋ฉด 4๊ฐ€์ง€์˜ ์ƒํƒœ๊ฐ€ ์กด์žฌํ•œ๋‹ค.
    • ๋น„์˜์†์ƒํƒœ : new OR Transient ์ƒํƒœ
    • ์˜์†์ƒํƒœ : managed ์ƒํƒœ
    • ์ค€์˜์†์ƒํƒœ : deteched ์ƒํƒœ
    • ์‚ญ์ œ์ƒํƒœ : removed ์ƒํƒœ

๐Ÿ˜๋น„์˜์† ์ƒํƒœ (Transient ์ƒํƒœ)

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ํ•ด๋‹น ์˜์†์„ฑ๊ฐ์ฒด๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ์ง€ ์•Š๋Š” ์ƒํƒœ์ด๋‹ค. ๊ทธ ํ•„๋“œ๋Š” ์˜์†ํ™”์—๋Œ€ํ•ด์„œ ์ œ์™ธํ•˜๊ฒ ๋‹ค ๋ผ๋Š” ๋ง์ด๋‹ค.
  • ๋˜‘๊ฐ™์ด Transient ์ƒํƒœ๋ผ๊ณ ๋„ ํ•˜๋ฉฐ, New ์ƒํƒœ๋ผ๊ณ ๋„ ํ•œ๋‹ค.
  • ์‚ฌ์‹ค ์ด ์ƒํƒœ๋Š” ์—”ํ‹ฐํ‹ฐ๋ผ๊ธฐ ๋ณด๋‹ค ๋‹จ์ˆœํ•˜๋‚˜์˜ ์ž๋ฐ” object๋กœ ๋ถ„๋ฅ˜๋œ๋‹ค.
@Service
public class UserService {
    @Transactional
    public void put(){
        User user = new User();
        user.setName("newUser");
        user.setEmail("newUser@fast.com");
    }
}
  • ์œ„ ์ฝ”๋“œ์—์„œ User๊ฐ์ฒด๋Š” ๋น„์˜์†์ƒํƒœ์ด๋‹ค.

    @SpringBootTest
    class UserServiceTest {
      @Autowired
      private UserService userService;
    
      @Autowired
      private UserRepository userRepository;
    
      @Test
      void test() {
          userService.put();
          System.out.println(">>>>>> " + userRepository.findByEmail("newUser@fast.com"));
      }
    }
    Hibernate: 
      select
          user0_.id as id1_7_,
          user0_.created_at as created_2_7_,
          user0_.updated_at as updated_3_7_,
          user0_.email as email4_7_,
          user0_.gender as gender5_7_,
          user0_.name as name6_7_ 
      from
          user user0_ 
      where
          user0_.email=?
    >>>>>> null
  • select์ฟผ๋ฆฌ๊ฐ€ ์ž‘๋™์€ ํ•˜์ง€๋งŒ ์‹ค์ œ DB์˜ user๋Š” ์•„์ง ์—†๋‹ค๋Š”๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

  • DB์™€ ์—ฐ๊ฒฐ์ด ๋œ๊ฒŒ ์•„๋‹ˆ๋ผ ๋‹จ์ˆœํžˆ ์ž๋ฐ” ๊ฐ์ฒด๋กœ๋งŒ ์กด์žฌํ•˜๋‹ค๊ฐ€ Transactio์ด ์ข…๋ฃŒ๋˜๊ณ ๋‚˜๋ฉด ์“ธ๋ชจ๊ฐ€ ์—†์–ด์ ธ์„œ ์˜์†ํ™” ๋˜์ง€ ์•Š๊ณ  ๊ฐ€๋น„์ง€ ์ปฌ๋ž™ํ„ฐ๋ฅผ ํ†ตํ•ด์„œ ์‚ฌ๋ผ์ง€๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋œ๋‹ค.

๐Ÿ˜ฎ์˜์† ์ƒํƒœ (managed ์ƒํƒœ)

  • ํ•ด๋‹น ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์˜์†์„ฑ์ปจํ…์ŠคํŠธ์˜ ๊ด€๋ฆฌํ•˜์— ์žˆ๋‹ค๋Š” ๋œป์ด๋‹ค.

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๊ด€๋ฆฌํ•œ๋‹ค๋Š” ๋œป์€ ๊ฐ์ฒด์˜ ๋ณ€ํ™”๋ฅผ ๋ณ„๋„๋กœ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์•„๋„ DB์— ๋ฐ˜์˜์‹œํ‚จ๋‹ค.

      @Transactional
      public void put(){
          User user = new User();
          user.setName("newUser");
          user.setEmail("newUser@fast.com");
    
          userRepository.save(user);
      }
  • ๐Ÿคš ์ฐธ๊ณ ๋กœ save๋ฉ”์„œ๋“œ๋ฅผ ์จ๋„ ์˜์†์ƒํƒœ๋กœ ๊ด€๋ฆฌํ•˜๊ฒŒ๋œ๋‹ค. ์ด์œ ๋Š” SimpleJpaRepositoryํด๋ž˜์Šค์—์„œ ์ •์˜ํ•ด๋†“์€ save๋ฉ”์„œ๋“œ๋ฅผ ๋ณด๋ฉด EntityManager์— Persist, ์ฆ‰ ์ž…๋ ฅํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

  • ํ•˜์ง€๋งŒ ์˜์†ํ™”์— ๋Œ€ํ•ด ๋””ํ…Œ์ผํ•˜๊ฒŒ ๋ณด๊ธฐ ์œ„ํ•ด EntityManager๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•ด ์ฃผ์ž.

@Service
@RequiredArgsConstructor
public class UserService {

    private final EntityManager entityManager;

    private final UserRepository userRepository;


    @Transactional
    public void put() {
        User user = new User();
        user.setName("newUser");
        user.setEmail("newUser@fast.com");

//        userRepository.save(user);
        entityManager.persist(user);

        user.setName("newUserAfterPersist");    //persist ํ•œ ๋‹ค์Œ์— ์‹คํ–‰ํ•œ ์ฟผ๋ฆฌ๋„ flush๋œ๋‹ค.
    }
}
insert 
    into
        user
        (created_at, updated_at, email, gender, name) 
    values
        (?, ?, ?, ?, ?)

        ...
        ...
        ...
>>>>>> User(super=BaseEntity(createdAt=null, updatedAt=null), id=6, name=newUser, email=newUser@fast.com, gender=null)
  • insert ์ฟผ๋ฆฌ๊ฐ€ ์ž‘๋™ํ•˜๊ณ , select๊ฐ€ ์‹คํ–‰๋˜๋ฉด์„œ DB์—์„œ ๊ฐ’์„ ๋ถˆ๋Ÿฌ์˜ฌ์ˆ˜ ์žˆ๋‹ค.
  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ํ•ด๋‹น ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ƒํƒœ๊ฐ€ ๋˜์—ˆ๋‹ค.
  • ์˜์†ํ™” ํ•ด์„œ managed ์ƒํƒœ๋กœ ๋ฐ”๋€Œ๋ฉด ์–ด๋–ค ๋ณ€ํ™”๊ฐ€ ์ผ์–ด๋‚ ๊นŒ?
    • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ๋‚ด์—์„œ ๊ด€๋ฆฌ๋˜๋Š” ์—”ํ‹ฐํ‹ฐ๋Š” ์…‹ํ„ฐ๋ฅผ ํ†ตํ•ด ์—”ํ‹ฐํ‹ฐ๊ฐ์ฒด ์ •๋ณด๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด, ๋ณ„๋„๋กœ save๋ฅผ ํ•˜์ง€ ์•Š์•„๋„ DB ๋ฐ์ดํ„ฐ์™€ ์ •ํ™•์„ฑ์„ ๋งž์ถฐ์ค€๋‹ค.
    • ์˜์†ํ™” ๋˜์–ด์žˆ์œผ๋ฉด save๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š์•„๋„ ํŠธ๋žœ์ ์…˜์ด ๋๋‚˜๋ฉด flush๊ฐ€ ์ผ์–ด๋‚œ๋‹ค๋Š” ๊ฒƒ.
    • ์ฆ‰, ์ฟผ๋ฆฌ๊ฐ€ DB์™€ ๊ฐ™์•„์ง€๋Š” ์‹œ์ ์€ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ–ˆ์„๋•Œ๊ฐ€ ์•„๋‹ˆ๋ผ flush๋ ๋•Œ๋ผ๋Š” ์ ์ด ์ค‘์š”ํ•˜๋‹ค.
    • ์—ฌ๊ธฐ์„œ setName์ด persist์ดํ›„์— ๋“ค์–ด๊ฐ”์ง€๋งŒ ์‹คํ–‰๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์˜์†์„ฑ ์ปจํ…์Šค๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋”ํ‹ฐ ์ฒดํฌ๋ผ๊ณ  ํ•œ๋‹ค.

Dirty Check

  • ์˜์†์„ฑ ์ปจํ…์Šค๊ฐ€ ๊ฐ€์ง€๊ณ ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ๊ฐ์ฒด๋Š” ์ฒ˜์Œ ์ปจํ…์Šค๋ฅผ ๋กœ๋“œ๋ฅผ ํ• ๋•Œ ๊ฐ์ฒด๋ฅผ ์ผ์ข…์˜ ์Šค๋ƒ…์ƒท์œผ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ๋ณ€๊ฒฝ๋‚ด์šฉ์„ DB์— ์ ์šฉํ•˜๋Š” ์‹œ์  (flushํ•˜๋Š” ์‹œ์ )์— ํ•ด๋‹น ์Šค๋ƒ…์ƒท๊ณผ ํ˜„์žฌ ์—”ํ‹ฐํ‹ฐ๊ฐ’์„ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ ๊ฐ’์ด ๋ฐœ๊ฒฌ๋˜๋ฉด ๋ณ€๊ฒฝ๊ฐ’๋„ ์ ์šฉ์‹œํ‚ค๋Š” ์ฟผ๋ฆฌ๋ฅผ ๋•Œ๋ฆฐ๋‹ค.

๐Ÿ˜Š์ค€์˜์† ์ƒํƒœ (detached)

  • ์›๋ž˜ ์˜์†ํ™” ๋˜์—ˆ๋˜ ์ƒํƒœ๋ฅผ ๋ถ„๋ฆฌํ•ด์„œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ๋ฐ–์œผ๋กœ ๊บผ๋‚ด๋Š” ์ƒํƒœ
    ...
    ...
      @Transactional
      public void put() {
          User user = new User();
          user.setName("newUser");
          user.setEmail("newUser@fast.com");
    

// userRepository.save(user);
entityManager.persist(user);
entityManager.detach(user); // ์ค€ ์˜์†ํ™”

    user.setName("newUserAfterPersist");    //persist ํ•œ ๋‹ค์Œ์— ์‹คํ–‰ํ•œ ์ฟผ๋ฆฌ๋„ flush๋œ๋‹ค.
    entityManager.merge(user); // ์žฌ ์˜์†ํ™”

    entityManager.flush(); // clearํ•˜๊ธฐ ์ „์— flush()
    entityManager.clear(); // ๋ณ€๊ฒฝ ์ž‘์—…์— ๋Œ€ํ•œ ๊ฒƒ์„ ๋ชจ๋‘ clearํ•œ๋‹ค.
}

}

- entityManager๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” ๋‹ค๋ฅธ ์ƒํƒœ์— ๋Œ€ํ•œ ๋ฉ”์„œ๋“œ๋Š” ๋ชจ๋‘ springDataJpa์—์„œ ์ œ๊ณตํ•ด์ค€๋‹ค. ํ•˜์ง€๋งŒ detach๋Š” ๋”ฐ๋กœ ์ œ๊ณตํ•ด์ฃผ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ์—์„œ๋Š” ๊ตณ์ด detach ํ•˜์ง€์•Š๋Š”๋‹ค๋Š” ๋œป ์ด๋‹ค.
- detachedํ•˜๋ฉด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๋”์ด์ƒ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š”๋‹ค.
- ์ค€ ์˜์†์ƒํƒœ์˜ ์—”ํ‹ฐํ‹ฐ๋ผ๋„ ๋ช…์‹œ์ ์œผ๋กœ ๋‹ค์‹œ entityManager์˜ merge๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ๊ด€๋ฆฌํ•œ๋‹ค.
- clear๋ฅผ ์จ๋„ detach์™€ ๋น„์Šทํ•œ ํšจ๊ณผ๋ฅผ ๋ณด์ง€๋งŒ ๋ณ€๊ฒฝ ์ž‘์—…์— ๋Œ€ํ•œ ๋ชจ๋“  ๊ฒƒ์„ clearํ•˜๊ธฐ ๋•Œ๋ฌธ์— clearํ•˜๊ธฐ ์ „์— flush() ํ•ด์ฃผ๋Š”๊ฒƒ์ด ์ข‹๋‹ค.

### ์‚ญ์ œ์ƒํ…Œ(removed์ƒํƒœ)
- ์‚ญ์ œ ์ƒํƒœ๋Š” ๋”ฑํžˆ ํŠน๋ณ„ํ•œ ๊ฒƒ์€ ์—†๊ณ  ํ•ด๋‹น ์—”ํ‹ฐํ‹ฐ๋Š” ๋” ์ด์ƒ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๋Š” ์ƒํƒœ๊ฐ€ ๋œ๋‹ค.
    User user1 = userRepository.findById(1L).get();
    entityManager.remove(user1);
@Test
void test() {
    userService.put();

// System.out.println(">>>>>> " + userRepository.findByEmail("newUser@fast.com"));
userRepository.findAll().forEach(System.out::println);
}

'Dev > JPA' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

JPA Cascade  (0) 2022.03.02
JPA์—์„œ Transaction์˜ ์ „ํŒŒ  (0) 2022.03.02
์˜์†์„ฑ ์ปจํ…์ŠคํŠธ(Entity Cache)  (0) 2022.03.02
JPA M:N ์—ฐ๊ด€๊ด€๊ณ„  (0) 2022.03.02
JPA ์—ฐ๊ด€๊ด€๊ณ„ ์‚ดํŽด๋ณด๊ธฐ(1:1)  (0) 2022.03.02