JiwonDev

JPA #4 ์—”ํ‹ฐํ‹ฐ ๋งคํ•‘ (๊ฐ์ฒด-ํ…Œ์ด๋ธ” ๋งคํ•‘)

by JiwonDev

JPA๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”๊ณผ ๋งคํ•‘ํ•˜๊ธฐ๊ฐ€ ์ •๋ง ์‰ฝ๋‹ค. ์• ๋…ธํ…Œ์ด์…˜์œผ๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ฐ€๋Šฅํ•˜๋‹ค.

• ๊ฐ์ฒด์™€ ํ…Œ์ด๋ธ” ๋งคํ•‘: @Entity, @Table
• ํ•„๋“œ์™€ ์ปฌ๋Ÿผ ๋งคํ•‘: @Column
• ๊ธฐ๋ณธ ํ‚ค ๋งคํ•‘: @Id
• ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘: @ManyToOne,@JoinColumn

 

๐Ÿ“Œ @Entity

JPA์—์„œ ์‚ฌ์šฉํ•  ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค๋ฅผ ์ง€์ •ํ•œ๋‹ค. ๋ฐ˜๋“œ์‹œ ๋ถ™์—ฌ์ค˜์•ผํ•˜๋ฉฐ ์—†๋‹ค๋ฉด ๊ฐ์ฒด๋ฅผ JPA๋กœ ๋‹ค๋ฃฐ ์ˆ˜ ์—†๋‹ค.

@Entity(name = "์ด๋ฆ„") ์œผ๋กœ JPA์—์„œ ์“ธ ์—”ํ‹ฐํ‹ฐ ์ด๋ฆ„์„ ์ง€์ •ํ•ด์ค„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ƒ๋žตํ•˜๋ฉด ํด๋ž˜์Šค๋ช…์„ ์ด๋ฆ„์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

  • ๋‹จ, ๋ฆฌํ”Œ๋ ‰์…˜์„ ์ด์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— [public ๋˜๋Š” protected ์ธ ๊ธฐ๋ณธ์ƒ์„ฑ์ž]๊ฐ€ ํ•„์ˆ˜์ด๋‹ค.
  • ๋˜ํ•œ ์‚ฌ์šฉํ•˜๋Š” ํ•„๋“œ, ํด๋ž˜์Šค์— final์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ํ”„๋ก์‹œ ์ƒ์„ฑ ๋ถˆ๊ฐ€๋Šฅ.
  • enum, interface, inner ํด๋ž˜์Šค ๋˜ํ•œ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค.

๋‚ด๋ถ€์ ์œผ๋กœ CGLIB๋“ฑ์„ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ์ค‘๊ฐ„์— ์—…๋ฐ์ดํŠธ๋˜๋ฉฐ ๋ฆฌํ”Œ๋ ‰์…˜ ๊ธฐ์ˆ ์ด ๋ฐ”๋€” ์ˆ˜๋„ ์žˆ๊ธฐ์— ๊ฐ„๋žตํ•˜๊ฒŒ๋งŒ ์•Œ๊ณ  ๋„˜์–ด๊ฐ€์ž.

// JPA ์–ด๋…ธํ…Œ์ด์…˜์€ ์ž๋ฐ” ํ‘œ์ค€ persistence์— ํฌํ•จ๋˜์–ด์žˆ๋‹ค.
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity // ๋ณดํ†ต ์ƒ๋žตํ•ด์„œ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค. ํด๋ž˜์Šค๋ช…์„ ์ด๋ฆ„์œผ๋กœ ์‚ฌ์šฉ
public class Member { 
   @Id 
   private Long id; 
   
   @Column(name = "name") 
   private String username; 
   
   private Integer age; 
   
   @Enumerated(EnumType.STRING) 
   private RoleType roleType; 
   
   @Temporal(TemporalType.TIMESTAMP) 
   private Date createdDate; 
   
   @Temporal(TemporalType.TIMESTAMP) 
   private Date lastModifiedDate; 
   
   @Lob 
   private String description; 
   
   //Getter, Setter… 
}

 

 

๐Ÿ“Œ@Table

์—”ํ‹ฐํ‹ฐ์™€ ๋งคํ•‘ํ•  ํ…Œ์ด๋ธ”์„ ์ง€์ •ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค.

@Table(name= "ํ…Œ์ด๋ธ”๋ช…" ) ์œผ๋กœ ํ…Œ์ด๋ธ”์„ ์ง€์ •ํ•ด์ค„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ƒ๋žตํ•˜๋ฉด Entity ์ด๋ฆ„์„ ํ…Œ์ด๋ธ”๋ช…์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

@Index๋กœ ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ @UniqueConstraint๋ฅผ ์ด์šฉํ•ด ํŠน์ • ์นผ๋Ÿผ์— ์ œ์•ฝ ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

ํŠน์ •์นผ๋Ÿผ ์ œ์•ฝ์กฐ๊ฑด์€ @Column(unique= ... ) ๋กœ๋„ ๊ฑธ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ œ์•ฝ์กฐ๊ฑด ์ด๋ฆ„์„ค์ •์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

์ด๋ ‡๊ฒŒ ์ œ์•ฝ์กฐ๊ฑด ์ด๋ฆ„์ด UUID๋กœ ๋ฐ•ํ˜€๋ฒ„๋ฆฐ๋‹ค. @Table์„ ์ด์šฉํ•ด์„œ ์ด๋ฆ„์„ ์ง€์ •ํ•ด์ฃผ์ž. (ex NAME_IS_UNIQUE)

@Entity
@Table(name="MEMBER", // ํ…Œ์ด๋ธ”๋ช…์„ MEMBER๋กœ ์ง€์ •
        uniqueConstraints = { // name, age ์นผ๋Ÿผ์— unique ์ œ์•ฝ์กฐ๊ฑด ์ถ”๊ฐ€
          @UniqueConstraint(name = "NAME_AGE_UNIQUE", columnNames = {"NAME", "AGE"} )
        })
public class Member {
    ...
}
@Table(indexes = {@Index(columnList="mycol1"), @Index(columnList="mycol2")})

 

โœ” JPA์˜ ํ…Œ์ด๋ธ” ์ž๋™ ์ƒ์„ฑ ๊ธฐ๋Šฅ (ddl.auto)

์ฐธ๊ณ ๋กœ JPA๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋งŒ๋“ค์–ด๋‘” ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•˜์—ฌ ํ…Œ์ด๋ธ”์„ ์ž๋™ ์ƒ์„ฑ(=DDL ์ƒ์„ฑ)ํ•  ์ˆ˜ ์žˆ๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ์‹œ์ ์— @Entity๋ฅผ ์ฝ์–ด DB์— DDL์„ ๋‚ ๋ ค์„œ ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•œ๋‹ค. ์•„๋ž˜ ์˜ต์…˜์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

* ์šด์˜์„œ๋ฒ„์—์„œ๋Š” ์ ˆ๋Œ€๋กœ ์‚ฌ์šฉํ•ด์„œ๋Š” ์•ˆ๋˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค. ์ž˜๋ชปํ•˜๋‹ค๊ฐ„ ์šด์˜์ค‘์ธ DB๊ฐ€ ์‚ญ์ œ๋˜๊ณ  ๋‹ค์‹œ ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ๋‹ค.

persistence.xml ๋˜๋Š” application.yml์—์„œ ํ•ด๋‹น ์˜ต์…˜์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿ“Œ @Id

ํ…Œ์ด๋ธ”์— ํ•„์ˆ˜ ๊ฐ’์ธ ๊ธฐ๋ณธํ‚ค๋ฅผ ์ง€์ •ํ•œ๋‹ค. (์—†๋‹ค๋ฉด IntelliJ์—์„œ ์นœ์ ˆํ•˜๊ฒŒ ์˜ค๋ฅ˜๋ฅผ ๋„์›Œ์ค€๋‹ค.)

๊ธฐ๋ณธํƒ€์ž…(int, String)์ด๋‚˜ ๊ธฐ๋ณธ ๋ž˜ํผํƒ€์ž… (Interger)์„ ๊ธฐ๋ณธํ‚ค๋กœ ์ง€์ •ํ•ด ์ค„ ์ˆ˜ ์žˆ๋‹ค.

๊ฐ์ฒด์—๋Š” Null์ด ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ๊ธฐ๋ณธ ํƒ€์ž…๋ณด๋‹ค๋Š” ๋ž˜ํผํƒ€์ž… (Long, Interger)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฑธ ๊ถŒ์žฅํ•œ๋‹ค.

 

๊ฐ„ํ˜น ๋ž˜ํผํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด boxing/ unboxing ๊ณผ์ • ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ์ด ๋‚˜๋น ์ง€๋Š”๊ฒŒ ์•„๋‹Œ๊ฐ€ ๊ฑฑ์ •ํ•˜๋Š” ์‚ฌ๋žŒ๋„ ์žˆ๋Š”๋ฐ,  ์ด๋Š” DB I/O์— ๋น„ํ•˜๋ฉด ๋งค์šฐ ๋น ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๋ณ‘๋ชฉ์ด ์ƒ๊ธฐ์ง€ ์•Š๋Š”๋‹ค. ์˜คํžˆ๋ ค null์„ ์ œ๋Œ€๋กœ ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ•ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ๊ฐ€ ํ›จ์”ฌ ํฌ๊ณ , ํ•ด๊ฒฐํ•˜๊ธฐ ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๊ธ‰์  ๋ž˜ํผํƒ€์ž…์„ ์“ฐ๋Š” ๊ฑธ ๊ถŒ์žฅํ•œ๋‹ค.

 

๊ทธ ์™ธ Date, BingDecimal ๊ฐ™์€ ๊ฒƒ๋„ ๊ธฐ๋ณธํ‚ค๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์ž˜ ์‚ฌ์šฉํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค.

๊ธฐ๋ณธ ํ‚ค์˜ ์ œ์•ฝ์กฐ๊ฑด์€ null์ด ๋˜๋ฉด ์•ˆ๋˜๊ณ , ์œ ์ผํ•ด์•ผํ•˜๋ฉฐ, ๋ฏธ๋ž˜์—๋„ ๋ณ€ํ•  ์ผ์ด ์—†์–ด์•ผ ํ•œ๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด ์ฃผ๋ฏผ๋“ฑ๋ก๋ฒˆํ˜ธ, ํ•™๋ฒˆ ๊ฐ™์€ ๊ฒƒ๋„ ๋จผ ๋ฏธ๋ž˜์—๋Š” ๋ณ€ํ•ด๋ฒ„๋ฆด ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์–ด ๊ธฐ๋ณธํ‚ค๋กœ ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค.

๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•˜๋”๋ผ๋„ [๋น„์ฆˆ๋‹ˆ์Šค์— ์˜๋ฏธ์žˆ๋Š” ๋ฐ์ดํ„ฐ]๋ฅผ ํ‚ค๋กœ ์‚ฌ์šฉํ–ˆ๋‹ค๊ฐ€๋Š”, ์ถ”ํ›„์— ๋ฒ•์ ์ธ ๋ฌธ์ œ๋‚˜ ๊ฐœ์ธ์ •๋ณด ๋•Œ๋ฌธ์— ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ๋  ๊ฒฝ์šฐ DB๋ฅผ ์ •๋ง ํฌ๊ฒŒ ์†๋ด์•ผํ•  ์ˆ˜๋„ ์žˆ๋‹ค. 

 

๊ทธ๋ž˜์„œ ๋ณดํ†ต [ํ‚ค ์ƒ์„ฑ์ „๋žต์„ ์‚ฌ์šฉํ•œ Long ํ‚ค] ์™€ [๋น„์ฆˆ๋‹ˆ์Šค์™€ ์ƒ๊ด€์—†๋Š” ๋Œ€์ฒดํ‚ค] ๋“ฑ์„ id๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฑธ ๊ถŒ์žฅํ•œ๋‹ค.

 

 

โœ” ๊ธฐ๋ณธํ‚ค ์ƒ์„ฑ ์ „๋žต @GeneratedValue

๊ธฐ๋ณธํ‚ค๋Š” ์ง์ ‘ ๋งŒ๋“ค์ง€ ์•Š๊ณ , DB ์ž๋™ ์ƒ์„ฑ์„ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๊ธฐ๋ณธํ‚ค ์ƒ์„ฑ์„ ์˜์กดํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // ๊ธฐ๋ณธ๊ฐ’์€ AUTO
private Long id;

์˜ต์…˜์€ ์ด 4๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.

  • AUTO(๊ธฐ๋ณธ๊ฐ’) : ์•„๋ž˜ 3๊ฐ€์ง€์ค‘ DB ๋ฐฉ์–ธ(dialect)์— ๋”ฐ๋ผ ์ž๋™ ์ง€์ •.
  • IDENTITY : ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ํ‚ค ์ƒ์„ฑ์„ ์œ„์ž„. DB๊ฐ€ ์•Œ์•„์„œ ์ฒ˜๋ฆฌํ•ด๋ผ (MySQL, PostgreSQL, SQL Server, DB2)
     โžก JPA ์ฟผ๋ฆฌ : id varchar(255) generated by default as identity
     โžก MySQL ์ฟผ๋ฆฌ : id varchar(255) not null auto_increment
    * insert๋ฅผ ํ•˜์ง€ ์•Š์œผ๋ฉด id ๊ฐ’์ด ๋ฌด์—‡์ธ์ง€ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์“ฐ๊ธฐ ์ง€์—ฐ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ๋ฐ”๋กœ DB์— flush ๋œ๋‹ค.
    ๋‹ค๋งŒ ํ‚ค ์ƒ์„ฑ์‹œ ๋ฐœ์ƒํ•˜๋Š” ์“ฐ๊ธฐ์ง€์—ฐ์€ ์‹ค์ œ ์„œ๋น„์Šค์—๋Š” ์„ฑ๋Šฅ ์ฐจ์ด๊ฐ€ ๊ฑฐ์˜ ์—†์–ด์„œ ๋ฌด์‹œํ•˜๊ณ  ์‚ฌ์šฉํ•ด๋„ ํฐ ์ƒ๊ด€์€ ์—†๋‹ค.
    * JDBC3๋ถ€ํ„ฐ ์ถ”๊ฐ€๋œ getGeneratedKeys๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— [insert SQL+ select key] ๋‘ ์ฟผ๋ฆฌ๋ฅผ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•œ๋‹ค.
  • SEQUENCE : ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‹œํ€€์Šค ์˜ค๋ธŒ์ ํŠธ ์‚ฌ์šฉ (Oracle, ๋‹จ @SequenceGenerator ๋กœ DB ์‹œํ€ธ์Šค์™€ ์—ฐ๋™ ํ•„์š”)
     โžก id๋ฅผ ์‹œํ€ธ์Šค์—์„œ ์กฐํšŒํ•ด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์ €์žฅํ•œ๋‹ค.
     โžก ์‹œํ€€์Šค ์˜ค๋ธŒ์ ํŠธ๋„ ๋ณดํ†ต 1๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๊ณ , +1 ๋กœ ์ฆ๊ฐ€๋˜๊ธดํ•˜์ง€๋งŒ ๊ฐœ๋ฐœ์ž๊ฐ€ ์›ํ•œ๋‹ค๋ฉด ์ด ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜๋„ ์žˆ๋‹ค. 
    * ์‹œํ€€์Šค๋งŒ DB์—์„œ ๊ฐ€์ ธ์˜ค๋ฉด ๋˜๊ธฐ์— ์ฟผ๋ฆฌ๋Š” ์“ฐ๊ธฐ์ง€์—ฐ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
@Entity
@SequenceGenerator(
    name = "BOARD_SEQ_GENERATOR", // ์‚ฌ์šฉํ•  sequence ์ด๋ฆ„
    sequenceName = "BOARD_SEQ", // ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค sequence ์ด๋ฆ„
    initialValue = 1, allocationSize = 1
)
public class Board{
    @Id
    @GeneratedValue(
        strategy = GenerationType.SEQUENCE,
        generator = "BOARD_SEQ_GENERATOR" // ์œ„์˜ sequence ์ด๋ฆ„
    )
    private Long id;
}

โžก ์•„๋ฌด๋ฆฌ ์‹œํ€€์Šค๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค๊ณ  ํ•ด๋„, DB์— ๋งค๋ฒˆ ์‹œํ€€์Šค ๊ฐ’์„ ์š”์ฒญ์„ ํ•˜๋Š”๊ฒŒ ๋„คํŠธ์›Œํฌ ๋น„์šฉ์ด ๋ถ€๋‹ด์Šค๋Ÿฌ์šธ ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ž˜์„œ allocationSize๋ผ๋Š” ์˜ต์…˜์„ ์ด์šฉํ•ด์„œ DB์— ๋ฏธ๋ฆฌ ์‹œํ€€์Šค ๊ฐ’์„ 50๊ฐœ๋ฅผ ๋งŒ๋“ค์–ด๋†“๊ณ  ํ•œ๋ฒˆ์— ๋ฐ›์•„์™€์„œ ์‚ฌ์šฉํ•œ๋‹ค.

allocationSize๊ฐ€ 50์ด๋ฉด, 1์— DB์—์„œ ์‹œํ€ธ์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ๋งˆ์ง€๋ง‰ 51์„ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์‚ฌ์šฉํ•  ๋•Œ ๋‹ค์‹œ DB์— ์ ‘๊ทผํ•œ๋‹ค.

์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์—์„œ ๋™์‹œ์— ์‚ฌ์šฉํ•œ๋‹ค ํ•˜๋”๋ผ๋„, ํ• ๋‹น๋ฐ›์€ ์‹œํ€ธ์Šค๊ฐ€ ๋‹ค๋ฅด๊ธฐ ๋–„๋ฌธ์— (1~51, 52~100) ๋™์‹œ์„ฑ ๋ฌธ์ œ๋Š” ์—†๋‹ค.

๋‹ค๋งŒ ์„œ๋ฒ„๊ฐ€ ์ค‘๊ฐ„์— ์ฃฝ์–ด๋ฒ„๋ฆฌ๋ฉด ํ• ๋‹น๋ฐ›์•˜๋‹ค๊ฐ€ ๋‚จ์€ ์‹œํ€ธ์Šค๋Š” ์˜์›ํžˆ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•œ๋‹ค. Size๋ฅผ ์ ๋‹นํžˆ ์„ค์ •ํ•˜์ž. 

 

  • TABLE : ํ‚ค ์ƒ์„ฑ์šฉ ํ…Œ์ด๋ธ” ์‚ฌ์šฉ ( @TableGenerator ํ•„์š”)
    DB์—์„œ ์‹œํ€ธ์Šค ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ, ์ง์ ‘ ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค์–ด์„œ ์‹œํ€ธ์Šค์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.
    Table์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ผ๋ฟ, DB ์‹œํ€ธ์Šค ์˜ค๋ธŒ์ ํŠธ์™€ ์‚ฌ์šฉ๋ฒ•์€ ๋™์ผํ•˜๋‹ค. ๋‹ค๋งŒ ์„ฑ๋Šฅ์ด ํ›จ์”ฌ ๊ตฌ๋ ค์„œ ์ž˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.
/* ์„ฑ๋Šฅ์ด ๊ตฌ๋ฆฐ ๋Œ€์‹ , ๊ทธ๋ƒฅ ํ…Œ์ด๋ธ”์„ ๋งŒ๋“œ๋Š”๊ฑฐ๋ผ ๋ชจ๋“  DB์— ์ ์šฉ๊ฐ€๋Šฅ */
@Entity
@TableGenerator(
    name = "MY_BOARD_SEQ_GENERATOR", // ์‚ฌ์šฉํ•  table sequence ์ด๋ฆ„
    table = "MY_BOARD_SEQ", // ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค table ์ด๋ฆ„
    pkColumnValue = "BOARD_SEQ", allocationSize = 1
)
public class Board{
    @Id
    @GeneratedValue(
        strategy = GenerationType.TABLE,
        generator = "MY_BOARD_SEQ_GENERATOR" // ์œ„์˜ sequence ์ด๋ฆ„
    )
    private Long id;
}

 

 

 

๐Ÿ“Œ @Column

ํ•„๋“œ์™€ ์นผ๋Ÿผ์„ ๋งค์นญํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. @Column์„ ์ด์šฉํ•ด์„œ ์ œ์•ฝ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹น์—ฐํžˆ JPA ์‹คํ–‰ ๋กœ์ง์— ์˜ํ–ฅ์„ ์ฃผ์ง€๋Š” ์•Š๋Š”๋‹ค. ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•  ๋•Œ (=์ž๋™ DDL ์ƒ์„ฑ์„ ์‚ฌ์šฉํ•  ๋•Œ) ์‚ฌ์šฉ๋œ๋‹ค.

์—ฌ๋‹ด์ด์ง€๋งŒ @Table์˜ ์ธ๋ฑ์Šค๋‚˜ @Column์„ ์ ์–ด๋‘๋ฉด DB๋ฅผ ํ™•์ธํ•˜์ง€ ์•Š์•„๋„ ๊ฐœ๋ฐœ์ž๊ฐ€ ์‰ฝ๊ฒŒ ์ •๋ณด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

โœ” ๊ฐ์ฒด - ํ…Œ์ด๋ธ” ์ด๋ฆ„๋ณ€๊ฒฝ ์ „๋žต (naming_strategy)

๋ฌผ๋ก  @Column์„ ์ƒ๋žตํ•ด๋„ ๋œ๋‹ค. ์•Œ์•„์„œ ํŠน์ • ๊ทœ์น™์— ๋”ฐ๋ผ ํ…Œ์ด๋ธ”๊ณผ ๊ฐ์ฒด๋ฅผ ๋งคํ•‘๋˜๋„๋ก ๋™์ž‘ํ•œ๋‹ค.

 

๋ณดํ†ต ๊ฐ์ฒด๋Š” ์นด๋ฉœ์ผ€์ด์Šค(myHomeTown)์„ ์‚ฌ์šฉํ•˜๊ณ , DB๋Š” ์–ธ๋”์Šค์ฝ”์–ด(MY_HOME_TOWN)์„ ์“ฐ๋Š”๊ฒŒ ์ผ๋ฐ˜์ ์ธ๋ฐ. ๋งŒ์•ฝ ๋‹ค๋ฅด๊ฒŒ ๋ณ€ํ™˜ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด naming_strategy ์˜ต์…˜์„ ํ†ตํ•ด ์ ์ ˆํ•˜๊ฒŒ ๋ณ€ํ™˜ ๊ฐ€๋Šฅํ•˜๋‹ค.

  • ImprovedNamingStrategy : camelCase๋ฅผ CAMEL_CASE๋กœ ๋ณ€๊ฒฝ
  • SpringPhysicalNamingStrategy (์Šคํ”„๋ง์šฉ ์˜ต์…˜, ๊ธฐ๋ณธ๊ฐ’) : camelCase๋ฅผ CAMEL_CASE๋กœ ๋ณ€๊ฒฝ. (์œ„์—๊ฑธ ์ƒ์†ํ•ด์„œ๋งŒ๋“ฆ)
  • PhysicalNamingStrategyStandardImpl (์Šคํ”„๋ง์šฉ ์˜ต์…˜) : ๋ณ€๊ฒฝ์—†์ด ๋ณ€์ˆ˜์ด๋ฆ„์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ
  • ๊ฑฐ์˜ ์‚ฌ์šฉํ•  ์ผ์€ ์—†์ง€๋งŒ ์ด๋ฆ„ ์ „๋žต ํด๋ž˜์Šค๋ฅผ ์ปค์Šคํ…€ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ๊ถ๊ธˆํ•˜๋ฉด ๊ฒ€์ƒ‰ํ•ด๋ณด๋„๋ก ํ•˜์ž.
// resource/META-INFO/persistence.xml
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"></property>

// resource/application.yml
jpa:
    hibernate:
    naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

 

name, nullable, length ์ •๋„๋ฅผ ์ž์ฃผ ์“ด๋‹ค. unique๋„ ์ข…์ข… ์“ฐ์ง€๋งŒ, @Table ๋กœ ์„ค์ •ํ•˜๋Š”๊ฑธ ๊ถŒ์žฅํ•จ.

public class Member {
 
    // ๊ธฐ๋ณธํ‚ค ๋งคํ•‘
    @Id
    @Column(name = "ID")
    private String id;
 
    // not null, varchar(10)
    @Column(name = "NAME", nullable = false, length = 10)
    private String username;
}

 

 

๐Ÿ“Œ [DB ์นผ๋Ÿผ]๊ณผ [๊ฐ์ฒด ํ•„๋“œ] ๋งคํ•‘ํ•˜๊ธฐ

@Column ๋ง๊ณ  ๋‹ค์–‘ํ•œ ๋งคํ•‘ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ œ๊ณตํ•ด์ค€๋‹ค.

Lob์€ Large Object์˜ ์•ฝ์ž๋กœ ์ด๋ฏธ์ง€, ๋™์˜์ƒ, ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ๋“ฑ์„ ์˜๋ฏธํ•œ๋‹ค. (ex CLOB = Char Lob)

public enum RoleType {
    ADMIN, USER
}
@Entity
public class Member {

    @Id
    private Long id;
    
    @Column(name = "name") // @Column์„ ์ด์šฉํ•˜์—ฌ ์ œ์•ฝ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ํ…Œ์ด๋ธ”๊ณผ ๋งคํ•‘ํ•œ๋‹ค.
    private String username;
    
    private Integer age; // DB์— ์žˆ๋Š” ํƒ€์ž…์€ ๋ณ„๋‹ค๋ฅธ ์˜ต์…˜์ด ์—†์–ด๋„ ์•Œ์•„์„œ ์ฒ˜๋ฆฌ.
    
    // DB์—๋Š” Enum ํƒ€์ž…์ด๋ž€๊ฒŒ ์—†์œผ๋ฏ€๋กœ, ๋”ฐ๋กœ ์ง€์ •ํ•ด์ฃผ์–ด์—ฌํ•œ๋‹ค.
    @Enumerated(EnumType.STRING)
    private RoleType roleType;
    
    // DB๋Š” TIME, DATE, TIMESTAMP(์‹œ๊ฐ„+๋‚ ์งœ)๋กœ ๊ตฌ๋ถ„์ง€์–ด ์‚ฌ์šฉํ•œ๋‹ค.
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;
    
    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModifiedDate;
    
    @Lob
    private String description;
    
    //Getter, Setter… 
}

 

โœ” @Basic

DB ์นผ๋Ÿผ์— ๋งคํ•‘์„ ํ•  ๋•Œ์—๋Š” @Column์ด๋‚˜ @Table (* ์ด๋ฆ„์ง€์ •๊ฐ€๋Šฅ)์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

๋งŒ์•ฝ JPA Entity์— ํŠน์ • ์˜ต์…˜์„ ์ฃผ๊ณ ์‹ถ์€ ๊ฒฝ์šฐ @Basic์„ ์‚ฌ์šฉํ•œ๋‹ค.

@Lob @Basic(fetch = FetchType.EAGER) // optional = false ๋“ฑ์œผ๋กœ nullable ์„ค์ •๋„ ๊ฐ€๋Šฅ
private String profileImage;

์ด๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์นผ๋Ÿผ๊ณผ๋Š” ์ƒ๊ด€์—†์ด, ๊ทธ๋ƒฅ JPA ์ƒ์— ์ถ”๊ฐ€์ ์ธ ์˜ต์…˜์„ ์ค„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

  • @Column ์‚ฌ์šฉ์‹œ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ null์„ ํ—ˆ์šฉํ•˜๋ฉด ๋ฌด์กฐ๊ฑด null ํ—ˆ์šฉ์ด๋‹ค. ์„ ํƒ๊ถŒ์ด ์—†๋‹ค.
  • @Basic์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค null ์—ฌ๋ถ€์™€ ์ƒ๊ด€์—†์ด, JPA Entity ์ž์ฒด์— ์ œ์•ฝ์กฐ๊ฑด์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค.

 

 

โœ” ์ฃผ์˜์‚ฌํ•ญ

๋งŒ์•ฝ DB์— ์ €์žฅํ•˜์ง€ ์•Š๊ณ ์‹ถ๋‹ค๋ฉด, ๋ฉ”๋ชจ๋ฆฌ์—๋งŒ ๋‚จ๊ฒจ๋‘๋Š” @Transient๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. (์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.)

@Transient
private MyCacheMemory Temp

 

* ์ฐธ๊ณ ๋กœ Enumeratd๋Š” ๋ฐ˜๋“œ์‹œ STRING์œผ๋กœ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค.

์ˆœ์„œ(1,2,3)์„ ์‚ฌ์šฉํ•˜๋Š” ORDINAL๋Š”, Enum ๊ฐ์ฒด๋ฅผ ์ˆ˜์ •ํ•  ๋•Œ๋งˆ๋‹ค DB์— ์žˆ๋Š” ์‹๋ณ„์ž์˜ ์˜๋ฏธ๊ฐ€ ๋ฐ”๋€Œ๊ธฐ์— ํฐ์ผ ๋‚  ์ˆ˜์žˆ๋‹ค.

@Enumerated(EnumType.STRING) // ORDINAL โŒ 
private RoleType roleType;

 

@Temporal์€ Java8 ์ดํ›„ ๋ฒ„์ „์—๋Š” ์‚ฌ์šฉํ• ์ผ์ด ๊ฑฐ์˜ ์—†๋‹ค.

๊ทธ๋ƒฅ LocalDate, LocalDateTime ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•Œ์•„์„œ ์ฒ˜๋ฆฌ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค

 

@Lob์€ ๋”ฐ๋กœ ์ง€์ •ํ•˜๋Š” ์˜ต์…˜์ด ์—†๊ณ , ํƒ€์ž…์ด ๋ฌธ์ž๋ฉด CLOB, ๊ทธ ์™ธ๋Š” BLOB ( ๋ฐ”์ด๋„ˆ๋ฆฌ )๋กœ ์ž๋™ ๋งคํ•‘๋œ๋‹ค.

CLOB = Char Large Object, ๋ง ๊ทธ๋Œ€๋กœ ๋ฌธ์ž์—ด ํฐ ๊ฐ์ฒด..ใ…‹ใ…‹

 

๐Ÿ“Œ @Embedded (์ปดํฌ๋„ŒํŠธ)

๋ญ ์ฐจ๊ทผ์ฐจ๊ทผ ๋ฐฐ์›Œ๋‚˜๊ฐˆ๊ฑฐ์ง€๋งŒ, ์ด๋ฒˆ ๊ธ€์—์„œ ๋ฐฐ์šด ๊ฑธ ์‚ฌ์šฉํ•œ ์ตœ์ข…์ ์ธ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๋น„์Šทํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ์งˆ๊ฒ๋‹ˆ๋‹ค.

// ์ž„๋ฒ ๋””๋“œ ํƒ€์ž… ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์„ ๋•Œ
@Entity
public class Member {
  
  @Id @GeneratedValue
  private Long id;
  
  private String name;
  
  // ๊ทผ๋ฌด ๊ธฐ๊ฐ„
  LocalDate startDate;
  LocalDate endDate;
  
  // ์ง‘ ์ฃผ์†Œ ํ‘œํ˜„
  private String city;
  private String street;
  private String zipcode;
  // ...
}

ํšŒ์›์ด ์œ„์™€ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ง„ ์ด์œ ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค๊ณ„ํ•˜๊ณ ์ž ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

"ํšŒ์› ์—”ํ‹ฐํ‹ฐ๋Š” ์ด๋ฆ„, [ ๊ทผ๋ฌด ๊ธฐ๊ฐ„ ], [ ์ง‘ ์ฃผ์†Œ ]๋ฅผ ๊ฐ€์ง„๋‹ค."

 

์‹ค์ œ ๋ฐ์ดํ„ฐ๋Š” '๊ทผ๋ฌด๊ธฐ๊ฐ„', '์ง‘ ์ฃผ์†Œ'๋ผ๋Š” ํ•˜๋‚˜์˜ ๊ฐ’์œผ๋กœ ๋‹ค๋ฃจ๊ธฐ์—๋Š” ๊นŒ๋‹ค๋กญ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋Ÿฐ Entity๊ฐ€ ๋งŒ๋“ค์–ด์ง„๊ฑฐ์ฃ .

 

"ํšŒ์› ์—”ํ‹ฐํ‹ฐ๋Š” ์ด๋ฆ„, [๊ทผ๋ฌด ์‹œ์ž‘์ผ, ๊ทผ๋ฌด ์ข…๋ฃŒ์ผ], [์ฃผ์†Œ ๋„์‹œ, ์ฃผ์†Œ ๋™ํ˜ธ์ˆ˜, ์šฐํŽธ ๋ฒˆํ˜ธ]๋ฅผ ๊ฐ€์ง„๋‹ค."

 

๋ฌด์–ธ๊ฐ€ ์–ด์ƒ‰ํ•˜์ง€ ์•Š์œผ์‹ ๊ฐ€์š”? ํšŒ์›์ด '์ง‘ ์ฃผ์†Œ'๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ๋Š” ์žˆ์ง€๋งŒ, '์„œ์šธ', '906ํ˜ธ' ์ด๋Ÿฐ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‹จ๋…์œผ๋กœ ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์„๊นŒ์š”?

 

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

 

 

โœจ ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด JPA์—์„œ๋Š” @Embedded ํƒ€์ž… (์ปดํฌ๋„ŒํŠธ)๋ฅผ ์ œ๊ณตํ•ด์ค๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•ด์„œ DB ํ…Œ์ด๋ธ”์ด ๋” ์ƒ์„ฑ๋˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด๊ณผ ๋™์ผํ•˜๊ฒŒ ๋งคํ•‘ํ•ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

// ์ž„๋ฒ ๋””๋“œ ํƒ€์ž… ์‚ฌ์šฉ
@Entity
public class Member {
  
  @Id @GeneratedVAlue
  private Long id;
  private String name;
  
  @Embedded
  private Period workPeriod;	// ๊ทผ๋ฌด ๊ธฐ๊ฐ„
  
  @Embedded
  private Address homeAddress;	// ์ง‘ ์ฃผ์†Œ
}

 

์ž„๋ฒ ๋””๋“œ ํƒ€์ž…์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์ •์˜ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

@Embeddable
public class Address {
  
  @Column(name="city") // ๋งคํ•‘ํ•  ์ปฌ๋Ÿผ ์ •์˜ ๊ฐ€๋Šฅ
  private String city;
  
  private String street;
  private String zipcode;
  
  public boolean isMetropolitanCity (City city) {
  // .. ๊ฐ’ ํƒ€์ž…์„ ์œ„ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค
  }
}

 

๋‹น์—ฐํžˆ ์ž„๋ฒ ๋””๋“œ ํƒ€์ž… ์•ˆ์—์„œ ๋‹ค๋ฅธ ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ž˜ ์„ค๊ณ„๋œ JPA Entity๋Š” ๋ณดํ†ต DB ํ…Œ์ด๋ธ”๋ณด๋‹ค ๋” ๋งŽ์€ ์ˆ˜์˜ ๊ฐ์ฒด๋ฅผ ๊ฐ€์ง€๋Š”๊ฒŒ ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค.

์‹ค์ œ ํ…Œ์ด๋ธ”์€ Member ํ•˜๋‚˜์ด๋‹ค.

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

JiwonDev

JiwonDev

ํ™œ๋™ํ•˜๊ธฐ