Intro. SpringDataJPA์™€ JPA

1๏ธโƒฃ SpringDataJPA ์‚ฌ์šฉ

// ๐Ÿ“ Entity ์ƒ์„ฑ
Member member = new Member();

member.setId("1");
member.setUsername("๋ง๋ž‘");

// ๐Ÿ“ Repository(DB) โ†’ ๊ฐ„๋‹จํ•œ์ฝ”๋“œ
memberRepository.save(mallang);
memberRepository.find();

2๏ธโƒฃ JPA ์‚ฌ์šฉ

// ๐Ÿ“ Entity ์ƒ์„ฑ
Member member = new Member();

member.setId("1");
member.setUsername("๋ง๋ž‘");

// ๐Ÿ“ EntityManagerFactory ์ƒ์„ฑ
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("JPA์‹ฌํ™”");

// ๐Ÿ“ EntityManager ์ƒ์„ฑ
EntityManager entityManager = entityManagerFactory.createEntityManager();

// ๐Ÿ“ ์ €์žฅ ๋ฐ ์กฐํšŒ
entityManager.persist("mallang"); // Entity ์˜์†ํ™”(์ €์žฅ)
entityManager.find(Member.class, 1L); // Entity ์กฐํšŒ
  • ํ”„๋กœ๊ทธ๋žจ์„ฑ๋Šฅ์„ ์œ„ํ•ด ์—ฌ๋Ÿฌ๊ฐœ์˜ ์Šค๋ ˆ๋“œ(ํ”„๋กœ๊ทธ๋žจ๋‚ด๋ถ€ ์ผ๊พผ)๊ฐ€ ๊ฐ™์ด ์ผํ•จ
    โ†’ ๋™์‹œ์„ฑ๋ฌธ์ œ ๋ฐœ์ƒ ๐Ÿšจ
    โ†’ ํŠน์ • ๋ฆฌ์†Œ์Šค ๊ณต์œ ํ•˜์ง€ ๋ชปํ•˜๊ฒŒํ•˜๋Š” ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•จ

  • โ‘  EntityManager : ๊ณต์œ ํ•˜๋ฉด ์•ˆ๋˜๋Š” ํŠน์ • ๋ฆฌ์†Œ์Šค๊ฐ€ ์žˆ์Œ

  • โ‘ก ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ โ†’ ํ•˜๋‚˜์˜ EntityManager ์ด์šฉ ๋ง‰์Œ โ›”๏ธ

  • โ‘ข EntityManagerFactory์—์„œ ํ•„์š”ํ•  ๋•Œ๋งˆ๋‹ค ์—ฌ๋Ÿฌ๊ฐœ์˜ EntityManager๋ฅผ ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉํ•จ โœ…


1 ์˜์†์„ฑ์ปจํ…์ŠคํŠธ

๐Ÿ“Œ ์˜์†์„ฑ์ปจํ…์ŠคํŠธ : Entity๋ฅผ ์˜๊ตฌ์ €์žฅํ•˜๋Š” ํ™˜๊ฒฝ

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊บผ๋‚ด์˜จ ๋ฐ์ดํ„ฐ๊ฐ์ฒด๋ฅผ ๋ณด๊ด€ํ•˜๋Š” ์—ญํ• 

  • EntityManager โ†’ Entity ์กฐํšŒ & ์ €์žฅ ์‹œ, Entity๋ฅผ ๋ณด๊ด€ํ•˜๊ณ  ๊ด€๋ฆฌํ•จ

1๏ธโƒฃ JPA Entity ์ƒํƒœ

๐Ÿ“ ๋น„์˜์†(New)

  • ์˜์†์„ฑ์ปจํ…์ŠคํŠธ์™€ ๊ด€๊ณ„์—†๋Š” ์ƒˆ๋กœ์šด ์ƒํƒœ
  • ๊ฐ์ฒด ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด๋„ ์‹ค์ œ DB์— ์˜ํ–ฅ โŒ (์ผ๋ฐ˜ Java ๊ฐ์ฒด)
// Entity ์ƒ์„ฑ
Member member1 = new Member();

member1.setId("mallang");
member1.setUsername("๋ง๋ž‘์ด");

๐Ÿ“ ์˜์†(Managed)

  • EntityManager โ†’ Entity๊ฐ€ ์˜์†์„ฑ์ปจํ…์ŠคํŠธ์— ์ €์žฅ๋˜์–ด ๊ด€๋ฆฌ๋˜๊ณ ์žˆ๋Š” ์ƒํƒœ
  • ๊ฐ์ฒด ๋ฐ์ดํ„ฐ ์ƒ์„ฑ & ๋ณ€๊ฒฝ โ†’ JPA๊ฐ€ ์ถ”์ ํ•˜๋ฉด์„œ, DB์— ๋ฐ˜์˜ํ•จ
// EntityManager -> ์˜์†์„ฑ์ปจํ…์ŠคํŠธ์— ์—”ํ‹ฐํ‹ฐ๊ฐ์ฒด ์ €์žฅ
entityManager.persist(member1);

๐Ÿ“ ์ค€์˜์†(Detached)

  • ์˜์†์„ฑ์ปจํ…์ŠคํŠธ์—์„œ ๊ด€๋ฆฌํ•˜๋‹ค๊ฐ€ ๋ถ„๋ฆฌ๋œ ์ƒํƒœ
// Entity ์˜์†์„ฑ์ปจํ…์ŠคํŠธ์—์„œ ๋ถ„๋ฆฌ
entityManager.detach(member1);

// ์˜์†์„ฑ์ปจํ…์ŠคํŠธ ๋น„์šฐ๊ธฐ
entityManager.clear();

// ์˜์†์„ฑ์ปจํ…์ŠคํŠธ ์ข…๋ฃŒ
entityManager.close();

๐Ÿ“ ์‚ญ์ œ(Removed)

  • ์˜์†์„ฑ์ปจํ…์ŠคํŠธ์—์„œ ์‚ญ์ œ๋œ ์ƒํƒœ
entityManager.remove(member1);

์ถœ์ฒ˜ : ์ž๋ฐ”ORMํ‘œ์ค€JPA

2๏ธโƒฃ 1์ฐจ์บ์‹œ

์ถœ์ฒ˜ : ์ž๋ฐ”ORMํ‘œ์ค€JPA

  • DB๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ž‘์—… : ์ƒ๋Œ€์ ์œผ๋กœ ๋ถ€ํ•˜์™€ ๋น„์šฉ์ด ์‹ฌํ•œ ์ž‘์—… ๐Ÿšจ
    โ†’ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‹œ, DB ์‚ฌ์šฉํšŸ์ˆ˜๋ฅผ ์ตœ๋Œ€ํ•œ ์ค„์ด๋Š”๊ฒŒ ์ข‹์Œ โœ…

  • Java ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฐ์ดํ„ฐ์กฐํšŒ๋งˆ๋‹ค โ†’ DB๋กœ SELECT*FROMโ€ขโ€ขโ€ข ๋‚˜๊ฐ€๋Š” SQL Query๋ฅผ ์ตœ๋Œ€ํ•œ ์ค„์—ฌ์•ผํ•œ๋‹ค๋Š” ์˜๋ฏธ โญ๏ธ

๐Ÿ“Œ ์˜์†์„ฑ์ปจํ…์ŠคํŠธ ๋‚ด๋ถ€์˜ 1์ฐจ์บ์‹œ
1. find("member1") ๋กœ์ง Request โ†’ 1์ฐจ์บ์‹œ ์šฐ์„ ์กฐํšŒ
2. 1์ฐจ์บ์‹œ์— ์žˆ์œผ๋ฉด โœ… , 1์ฐจ์บ์‹œ์—์„œ ์กฐํšŒํ•ด์„œ Response
3. 1์ฐจ์บ์‹œ์— ์—†์œผ๋ฉด โ›”๏ธ , DB๋กœ ์‹ค์ œ SQL Query๋ฅผ ๋‚ด๋ณด๋ƒ„
4. DB์—์„œ ์ง์ ‘ ์ฐพ์€ ๊ฐ’ Response ์ „, 1์ฐจ์บ์‹œ์— ์ €์žฅํ•˜๊ณ  Response
ย ย ย  (๋‹ค์Œ์ž‘์—… ๋•Œ DB๋กœ Query๋ฅผ ๋˜ ๋‚ ๋ฆฌ์ง€ ์•Š๊ธฐ์œ„ํ•ด)

3๏ธโƒฃ ์“ฐ๊ธฐ์ง€์—ฐSQL์ €์žฅ์†Œ

์ถœ์ฒ˜ : ์ž๋ฐ”ORMํ‘œ์ค€JPA

  • DB๋กœ SQL Query๋ฅผ ๋‚ด๋ณด๋‚ด๋Š” ์ผ์„ ์ตœ๋Œ€ํ•œ ์ค„์ด๊ธฐ ์œ„ํ•ด,
    ์—ฌ๋Ÿฌ๋ฒˆ DB๋ฅผ ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š๋„๋ก โ†’ ์˜์†์„ฑ์ปจํ…์ŠคํŠธ ๋‚ด๋ถ€์— ์“ฐ๊ธฐ์ง€์—ฐSQL์ €์žฅ์†Œ๋ฅผ ๋‘ 

๐Ÿ“Œ ์˜์†์„ฑ์ปจํ…์ŠคํŠธ ๋‚ด๋ถ€์˜ ์“ฐ๊ธฐ์ง€์—ฐSQL์ €์žฅ์†Œ
1. memberA, memberB Entity โ†’ ์˜์†ํ™”ํ•จ (persist())
2. entityManager.commit() โ†’ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
3. ๋‚ด๋ถ€์ ์œผ๋กœ ์“ฐ๊ธฐ์ง€์—ฐSQL์ €์žฅ์†Œ โžก๏ธ Flush
4. SQL Query(INSERT A, INSERT B) โ†’ DB๋กœ ๋ฐ˜์˜๋จ

4๏ธโƒฃ DirtyChecking

์ถœ์ฒ˜ : ์ž๋ฐ”ORMํ‘œ์ค€JPA

  • DirtyChecking โ†’ ๋ฐ์ดํ„ฐ์˜ ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•ด ์ž๋™์œผ๋กœ ์ˆ˜์ •ํ•ด์คŒ

  • JPA : 1์ฐจ์บ์‹œ + ์“ฐ๊ธฐ์ง€์—ฐSQL์ €์žฅ์†Œ โ†’ ๋ณ€๊ฒฝ & ์ˆ˜์ • ๊ฐ์ง€ํ•จ โญ๏ธ

๐Ÿ“Œ DirtyChecking
1. 1์ฐจ์บ์‹œ : Entity ๊ฐ์ฒด์ •๋ณด + Entity ์กฐํšŒ์‹œ์  ๋ฐ์ดํ„ฐ (์Šค๋ƒ…์ƒท) โ†’ ๋ชจ๋‘์ €์žฅ
2. Entity ๊ฐ์ฒด์ •๋ณด์™€ Entity ์กฐํšŒ์‹œ์  ๋ฐ์ดํ„ฐ ๋‹ค๋ฆ„ โ†’ ๋ณ€๊ฒฝ๋ฐœ์ƒ ํƒ์ง€
3. ๋ณ€๊ฒฝ์ด ํƒ์ง€๋˜๋ฉด, ํ•ด๋‹น ๋ณ€๊ฒฝ๋ถ€๋ฌธ์„ ๋ฐ˜์˜ํ•  ์ˆ˜ ์žˆ๋Š” UPDATE Query ์Šค์Šค๋กœ ์ž‘์„ฑํ•ด๋‘  (โ†’ ์“ฐ๊ธฐ์ง€์—ฐSQL์ €์žฅ์†Œ)

5๏ธโƒฃ ๋ฐ์ดํ„ฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‹จ ๋™์ผ์„ฑ๋ณด์žฅ

Member member1 = entityManager.find(Member.class, "mallang");
Member member2 = entityManager.find(Member.class, "mallang");

System.out.println(member1 == member2); // True
  • Entity ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฅด์ง€๋งŒ, ๋™์ผ์„ฑ์„ ๋ณด์žฅํ•จ

2 Entity Mapping ์‹ฌํ™”

1๏ธโƒฃ ๊ธฐ๋ณธ Entity Mapping

@Entity
@Table(name = "USER")
public class Member {
	
    @Id
    @Column(name = "user_id")
    private String id;
    
    private String username;
    
    private Integer age;
    
    @Enumerated(EnumType.STRING)
    private RoleType userRole;
    
    // Timestamped ํด๋ž˜์Šค ์ƒ์†ํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;
    
    @Temporal(TemporalType.TIMESTAMP)
    private Date modifiedDate;
    
}

๊ธฐ๋ณธ Entity ๊ด€๋ จ Annotation

AnnotationํŠน์ง•
@Entity- ๊ธฐ๋ณธ์ƒ์„ฑ์ž ํ•„์ˆ˜ (@NoArgsConstructor_ํŒŒ๋ผ๋ฏธํ„ฐ์—†๋Š”๊ธฐ๋ณธ์ƒ์„ฑ์ž)
- final, enum, interface ํด๋ž˜์Šค์— ์‚ฌ์šฉ๋ถˆ๊ฐ€ โ›”๏ธ
- ์ €์žฅํ•  ํ•„๋“œ โ†’ final ์‚ฌ์šฉ๋ถˆ๊ฐ€ โ›”๏ธ
@Table- Entity์™€ Mapping ํ•  ํ…Œ์ด๋ธ”์˜ ์ด๋ฆ„
- ์ƒ๋žต โ†’ ํด๋ž˜์Šค ๋ช…์ด ํ…Œ์ด๋ธ” ๋ช…์œผ๋กœ ๊ท€์†๋จ
@Column- ๊ฐ์ฒด ํ•„๋“œ โ†’ ํ…Œ์ด๋ธ” Column์— Mappingํ•˜๋Š”๋ฐ ์‚ฌ์šฉ
- ์ƒ๋žต๊ฐ€๋Šฅ
- ์ด๋ฆ„, Nullable, unique ๋“ฑ ์†์„ฑ ์‚ฌ์šฉ
@Enumerated- Java Enum์„ ํ…Œ์ด๋ธ”์—์„œ ์‚ฌ์šฉ
- STRING ์†์„ฑ : Enum ์ด๋ฆ„์„ Column์— ์ €์žฅํ•จ (Enum๋ณ€๊ฒฝ์—๋„ ์•ˆ์ „ํ•จ)
- ORDINAL ์†์„ฑ : Enum์— ๋Œ€์‘๋˜๋Š” ์ˆœ์„œ index๊ฐ’์„ Column์— ์ €์žฅํ•จ

2๏ธโƒฃ ๋‹จ๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„

@Entity
@Getter
@Setter
public class Member {
	
    @Id
    @Column(name = "member_id")
    private String id;
    
    private String username;
    
    @ManyToOne
    @JoinColumn(name = "team_id")
    private Team team;
    
    public void setTeam(Team team) {
    	this.team = team;
    }

}

@Entity
@Getter
@Setter
public class Team {
	
    @Id
    @Column(name = team_id)
    private String id;
    
    private String teamname;
    
}

๋‹จ๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„ ๊ด€๋ จ Annotation

AnnotationํŠน์ง•
@ManyToOne- N : 1 (๋‹ค๋Œ€์ผ) ๊ด€๊ณ„
- Optional ์†์„ฑ : false โ†’ ์—ฐ๊ด€๋œ Entity๊ฐ€ ํ•ญ์ƒ ์žˆ์–ด์•ผ ์ƒ์„ฑ๊ฐ€๋Šฅ
- fetch ์†์„ฑ : EAGER โ†’ (์—ฐ๊ด€๋œ๊ฒƒ๊นŒ์ง€)์ฆ‰์‹œ๋กœ๋”ฉ, LAZY โ†’ ์ง€์—ฐ๋กœ๋”ฉ
- cascade : ์˜์†์„ฑ์ „์ด
@JoinColumn- FK Mapping
- ์‹ค์ œ DB ๊ฐ์ฒดํ•„๋“œ โ†’ ๊ฐ์ฒดํ…Œ์ด๋ธ”์˜ FK๊ฐ€ ๋“ค์–ด๊ฐ
- name ์†์„ฑ : FK ๋ช…

3๏ธโƒฃ ์–‘๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„

@Getter
@Entity
@NoArgsConstructor // ํŒŒ๋ผ๋ฏธํ„ฐ์—†๋Š” ๊ธฐ๋ณธ์ƒ์„ฑ์ž
public class Member {
	
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false)
    private String memberName;
    
    @OneToMany(mappedBy = "member", fetch = FetchType.EAGER)
    private List<Orders> orders = new ArrayList<>();
    
    // ์ƒ์„ฑ์ž
    public Member(String memberName) {
    	this.memberName = memberName;
    }
    
}
@Getter
@Entity
@NoArgsConstructor
public class Orders {
	
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "food_id")
    private Food food;
    
    @ManyToOne
    @JoinColumn(name = "member_id")
    private Member member;
    
    // ์ƒ์„ฑ์ž
    public Orders(Food food, Member member) {
    	this.food = food;
        this.member = member;
    }
    
}
@Getter
@Entity
@NoArgsConstructor
public class Food {
	
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false)
    private String foodName;
    
    @Column(nullable = false)
    private int price;
    
    @OneToMany(mappedBy = "food", fetch = FetchType.EAGER)
    private List<Orders> orders = new ArrayList<>();
    
    // ์ƒ์„ฑ์ž
    public Food(String foodName, int price) {
    	this.foodName = foodName;
        this.price = price
    }

}

3 ํ”„๋ก์‹œ

๐Ÿ“Œ ํ”„๋ก์‹œ : ์ง€์—ฐ๋กœ๋”ฉ๊ธฐ๋Šฅ(fetch) ์‚ฌ์šฉ ์‹œ, ์‹ค์ œ Entity ๊ฐ์ฒด ๋Œ€์ƒ์— DB์กฐํšŒ๋ฅผ ์ง€์—ฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€์งœ๊ฐ์ฒด

  • Entity ์กฐํšŒ โ†’ ์—ฐ๊ด€๋œ Entity๊ฐ€ ํ•ญ์ƒ ์‚ฌ์šฉ๋˜์ง€ โŒ

  • ์—ฐ๊ด€๊ด€๊ณ„ Entity : ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ๋”ฐ๋ผ ์‚ฌ์šฉ๋  ๋•Œ๋„ ์žˆ์ง€๋งŒ, ์•„๋‹๋•Œ๋„ ์žˆ์Œ

  • JPA : ๋ถˆํ•„์š”ํ•œ DB ์กฐํšŒ๋ฅผ ์ค„์—ฌ ์„ฑ๋Šฅ์ตœ์ ํ™” โœ…

  • ์ง€์—ฐ๋กœ๋”ฉ : Entity๊ฐ€ ์‹ค์ œ ์‚ฌ์šฉ๋  ๋•Œ๊นŒ์ง€ DB์กฐํšŒ๋ฅผ ์ง€์—ฐํ•˜๋Š” ๋ฐฉ๋ฒ•

profile
๐ŸฑSunyeon-Jeong, mallang developer๐Ÿฐ

0๊ฐœ์˜ ๋Œ“๊ธ€