TIL/Spring

๐Ÿ“š 3/11(์›”) ๋‚ด์ผ๋ฐฐ์›€์บ ํ”„ Java-Spring 52์ผ์ฐจ TIL - SpringData JPA ๋‹ค์ด๋‚ด๋ฏน ์‚ฌ์šฉํ•˜๊ธฐ / @DynamicInsert์™€ @DynamicUpdate๋ž€?

zzu_dev 2024. 3. 12. 16:57

๐Ÿ“  ์˜ค๋Š˜์˜ ํ•™์Šต ํ‚ค์›Œ๋“œ 

  • SpringData JPA - @DynamicInsert
  • SpringData JPA - @DynamicUpdate

 

 

 

 

๐Ÿ“ @DynamicInsert, @DynamicUpdate๋ž€

  @DynamicInsert์™€ @DynamicUpdate๋Š” Hibernate์—์„œ ์ œ๊ณตํ•˜๋Š” ์ฃผ์„(Annotation)์œผ๋กœ, ์—”ํ„ฐํ‹ฐ์˜ ์ €์žฅ ๋ฐ ์ˆ˜์ • ๋™์ž‘์— ๋Œ€ํ•œ ์„ฑ๋Šฅ ๋ฐ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค. JPA์—์„œ ์—”ํ‹ฐํ‹ฐ์˜ ์ €์žฅ(insert) ๋ฐ ์—…๋ฐ์ดํŠธ(update) ์‹œ ์—”ํ‹ฐํ‹ฐ์˜ ๋ณ€ํ™”๊ฐ€ ์žˆ๋Š” ์ปฌ๋Ÿผ์— ๋Œ€ํ•ด์„œ๋งŒ SQL์„ ์‹คํ–‰ํ•˜๊ณ , ๋ณ€ํ™”๊ฐ€ ์—†๋Š” ์ปฌ๋Ÿผ์— ๋Œ€ํ•ด์„œ๋Š” ์‹คํ–‰ํ•˜์ง€ ์•Š๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค. ํ•„๋“œ๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ์„ฑ๋Šฅ์˜ ์ฐจ์ด๊ฐ€ ๋” ๋งŽ์ด ๋‚˜ํƒ€๋‚  ์ˆ˜ ์žˆ๋‹ค.

 

@DynamicInsert : ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์‚ฝ์ž…(INSERT)ํ•  ๋•Œ, ๋„์ด ์•„๋‹Œ ์†์„ฑ๋งŒ์„ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ๋™์  INSERT ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. INSERT๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ถˆํ•„์š”ํ•œ ์ปฌ๋Ÿผ์„ ์ œ์™ธํ•˜๊ณ  ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๋ฏ€๋กœ, ์‚ฝ์ž… ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

@DynamicUpdate: ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ˆ˜์ •(UPDATE)ํ•  ๋•Œ, ๋ณ€๊ฒฝ๋œ ์†์„ฑ๋งŒ์„ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ๋™์  UPDATE ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ๋ณ€๊ฒฝ๋œ ์†์„ฑ๋งŒ์„ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ๋™์  UPDATE๋Š” ๋ถˆํ•„์š”ํ•œ ์ปฌ๋Ÿผ์„ ์—…๋ฐ์ดํŠธํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ, ์ˆ˜์ • ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

 

 

 

 

 

 

๐Ÿ“ @DynamicInsert ์‚ฌ์šฉํ•ด๋ณด๊ธฐ 

  User ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ์–ด๋–ค ์‹์œผ๋กœ ์ฟผ๋ฆฌ๊ฐ€ ๋‚ ์•„๊ฐ€๋Š”์ง€ ํ™•์ธ์„ ํ•ด๋ณด์ž.

@DynamicInsert
@Entity
@Table
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class User {

  @Id @GenerateValue
  @Column
  private Long id;
  
  @Column
  private String username;
  
  @Column
  private String password;
  
}

 

 

 

 

    ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด์ž.

@Test
  void dynamicInsertTest() {
    // given
    var newUser = User.builder().username("user").build();

    // when
    userRepository.save(newUser);

    // then
    // ๋ถ€๋ถ„ ์ƒ์„ฑ ์ฟผ๋ฆฌ
  }

 

 

 

 

    ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ฟผ๋ฆฌ๊ฐ€ ์–ด๋–ค ์‹์œผ๋กœ ๋‚ ์•„๊ฐ€๋Š”์ง€ ํ™•์ธํ•ด ๋ณด์ž.

<@DynamicInsert ์ ์šฉ ์ „>

 

 

<@DynamicInsert ์ ์šฉ ํ›„>

 

 

@DynamicInsert ์ ์šฉ ์ „, ํ›„๋ฅผ ๋น„๊ตํ•ด ๋ณด๋ฉด ๋งŽ์€ ์ฐจ์ด๊ฐ€ ๋‚˜์ง€ ์•Š์ง€๋งŒ ํ•„๋“œ๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ๋” ์ฐจ์ด๊ฐ€ ๋งŽ์ด ๋‚˜๊ฒŒ ๋œ๋‹ค.

 

 

 

 

 

 

๐Ÿ“ @DynamicUpdate ์‚ฌ์šฉํ•ด ๋ณด๊ธฐ 

  User ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ์–ด๋–ค ์‹์œผ๋กœ ์ฟผ๋ฆฌ๊ฐ€ ๋‚ ์•„๊ฐ€๋Š”์ง€ ํ™•์ธ์„ ํ•ด๋ณด์ž.

@DynamicUpdate
@Entity
@Table
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class User {

  @Id @GenerateValue
  @Column
  private Long id;
  
  @Column
  private String username;
  
  @Column
  private String password;
  
}

 

 

 

 

    ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด์ž.

@Test
  void dynamicUpdateTest() {
    // given
    var newUser = User.builder().username("user").password("password").build();
    userRepository.save(newUser);

    // when
    newUser.updatePassword("new password");
    userRepository.save(newUser);

    // then
    // ๋ถ€๋ถ„ ์ˆ˜์ • ์ฟผ๋ฆฌ
  }

 

 

 

 

    ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ฟผ๋ฆฌ๊ฐ€ ์–ด๋–ค ์‹์œผ๋กœ ๋‚ ์•„๊ฐ€๋Š”์ง€ ํ™•์ธํ•ด ๋ณด์ž.

<@DynamicUpdate ์ ์šฉ ์ „>

 

<@DynamicUpdate ์ ์šฉ ํ›„>

 

 

@DynamicUpdate ์ ์šฉ ์ „, ํ›„๋ฅผ ๋น„๊ตํ•ด ๋ณด๋ฉด ๋งŽ์€ ์ฐจ์ด๊ฐ€ ๋‚˜์ง€ ์•Š์ง€๋งŒ ํ•„๋“œ๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ๋” ์ฐจ์ด๊ฐ€ ๋งŽ์ด ๋‚˜๊ฒŒ ๋œ๋‹ค.

 

 

 

 

 

 

- ์‚ฌ์šฉ ์‹œ ๊ณ ๋ คํ•ด์•ผ ํ•  ๊ฒƒ -
  ๋‹ค์ด๋‚ด๋ฏน ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ์Šค๋ƒ…์ƒท(Snapshot)์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , ์—”ํ‹ฐํ‹ฐ์˜ ๋ณ€๊ฒฝ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜์ง€ ์•Š๊ณ ๋„ ์ฟผ๋ฆฌ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค. ๋ณ€๊ฒฝ๋œ ํ•„๋“œ๋ฅผ ๋”ฐ๋กœ ์ถ”์ ํ•˜์ง€ ์•Š๊ณ ๋„ ์—”ํ„ฐํ‹ฐ์˜ ๋ชจ๋“  ํ•„๋“œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋™์ ์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

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

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ(Persistence Context)๋Š” ์—”ํ‹ฐํ‹ฐ์˜ ์ƒํƒœ๋ฅผ ์ถ”์ ํ•˜๊ณ , ์Šค๋ƒ…์ˆ์„ ์‚ฌ์šฉํ•˜์—ฌ ์—”ํ„ฐํ‹ฐ์˜ ๋ณ€๊ฒฝ ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•œ๋‹ค. ๋ณ€๊ฒฝ๋œ ์—”ํ‹ฐํ‹ฐ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ ค ๋™๊ธฐํ™”๋œ๋‹ค.

์ฆ‰, ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” ์Šค๋ƒ…์ƒท์„ ์‚ฌ์šฉํ•˜์—ฌ ์—”ํ„ฐํ‹ฐ์˜ ๋ณ€๊ฒฝ ์—ฌ๋ถ€๋ฅผ ๊ฐ์ง€ํ•˜๊ณ , ๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ์„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋™๊ธฐํ™”ํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํŠธ๋žœ์žญ์…˜์ด๋‚˜ Flush ์ž‘์—… ์‹œ์— ๋ณ€๊ฒฝ๋œ ํ•„๋“œ๋งŒ์„ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ํšจ์œจ์ ์ธ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ผ๊ด€๋œ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

  ํ•˜์ง€๋งŒ, ์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ JPA์˜ ๊ธฐ๋ณธ ๋™์ž‘์—๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์œผ๋ฉฐ, ์‹ค๋ฌด์—์„œ๋Š” ๊ฐœ๋ฐœ์ž์˜ ํŽธ์˜์™€ ์„ฑ๋Šฅ ์ตœ์ ํ™” ์ธก๋ฉด์—์„œ ์‚ฌ์šฉ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•˜๊ฒŒ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ @DynamicInsert์™€ @DynamicUpdate์˜ ์‚ฌ์šฉ ์œ ๋ฌด๋Š” ๊ฐœ์ธ๋ณ„๋กœ ์ƒํ™ฉ์— ๋งž๊ฒŒ ๊ฒฐ์ •ํ•˜๋ฉด ๋œ๋‹ค.