이 글은 김영한의 [자바 ORM 표준 JPA 프로그래밍 - 기본편] 수강하며 정리한 글입니다.

 

👉 기본 환경

- Language: Java

- DB: H2 Database

- IDE: IntelliJ

 

 

다대다 매핑

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
 
@Entity
public class Member {
 
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
 
    @Column(name = "USER_NAME")
    private String name;
 
    @ManyToMany
    @JoinTable(name = "MEMBER_PRODUCT")
    private List<Product> products = new ArrayList<>();
 
}
 
 
 

Member Entity

    - 연관 관계 주인

    - JoinTable 생성

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
 
@Entity
public class Product {
 
    @Id @GeneratedValue
    @Column(name = "PRODUCT_ID")
    private Long id;
 
    @Column(name = "PRODUCT_NAME")
    private String name;
 
    @ManyToMany(mappedBy = "products")
    private List<Member> members = new ArrayList<>();
 
}
 
 
 

Product Entity

    - 단순 참조를 위한 매핑

 

⭐ 관계형 데이터베이스에서 다대다 (Many-to-Many) 관계를 직접적으로 표현하는 것은 불가능

    ▶ 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야 함

 

중간 테이블에 새로운 컬럼을 추가하는 게 어려워 유연성이 떨어짐

    - @JoinTable을 통해서 PK, FK 관계 이외의 필드를 설정하기 어려움

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Hibernate: 
    
    create table Member (
       MEMBER_ID bigint not null,
        USER_NAME varchar(255),
        primary key (MEMBER_ID)
    )
 
Hibernate: 
    
    create table MEMBER_PRODUCT (
       members_MEMBER_ID bigint not null,
        products_PRODUCT_ID bigint not null
    )
 
Hibernate: 
    
    create table Product (
       PRODUCT_ID bigint not null,
        PRODUCT_NAME varchar(255),
        primary key (PRODUCT_ID)
    )
 
 
Hibernate: 
    
    alter table Member 
       add constraint FK332130jlg9s5hyeuk7gfgi052 
       foreign key (LOCKER_ID) 
       references Locker
 
Hibernate: 
    
    alter table MEMBER_PRODUCT 
       add constraint FKfmfxdrleengm9fi0691plhcwa 
       foreign key (products_PRODUCT_ID) 
       references Product
 
Hibernate: 
    
    alter table MEMBER_PRODUCT 
       add constraint FKp9hlrsu8hrsusdymar0ddcl9o 
       foreign key (members_MEMBER_ID) 
       references Member
 
 
 

Entity 실행 결과

 

 

⭐ 다대다 매핑은 일대다 + 다대일 매핑으로 풀어내야 함

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
 
@Entity
public class Member {
 
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
 
    @Column(name = "USER_NAME")
    private String name;
 
    @OneToMany(mappedBy = "member")
    private List<MemberProduct> memberProducts = new ArrayList<>();
 
}
 
 
 

Member Entity

    - Member : MemberProduct = 1: 다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
 
@Entity
public class Product {
 
    @Id @GeneratedValue
    @Column(name = "PRODUCT_ID")
    private Long id;
 
    @Column(name = "PRODUCT_NAME")
    private String name;
 
    @OneToMany(mappedBy = "product")
    private List<MemberProduct> memberProducts = new ArrayList<>();
 
}
 
 
 

Product Entity

    - Product : MemberProduct = 1: 다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import javax.persistence.*;
import java.time.LocalDateTime;
 
@Entity
public class MemberProduct {
 
    @Id @GeneratedValue
    private Long id;
 
    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;
 
    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;
 
    private int count;
    private int price;
 
    private LocalDateTime orderDate;
 
}
 
 
 

MemberProduct Entity

    - Member : MemberProduct = 1: 다

    - Product : MemberProduct = 1: 다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Hibernate: 
    
    create table Member (
       MEMBER_ID bigint not null,
        USER_NAME varchar(255),
        primary key (MEMBER_ID)
    )
 
Hibernate: 
    
    create table MemberProduct (
       id bigint not null,
        count integer not null,
        orderDate timestamp,
        price integer not null,
        MEMBER_ID bigint,
        PRODUCT_ID bigint,
        primary key (id)
    )
 
Hibernate: 
    
    create table Product (
       PRODUCT_ID bigint not null,
        PRODUCT_NAME varchar(255),
        primary key (PRODUCT_ID)
    )
 
 
Hibernate: 
    
    alter table Member 
       add constraint FK332130jlg9s5hyeuk7gfgi052 
       foreign key (LOCKER_ID) 
       references Locker
 
Hibernate: 
    
    alter table MemberProduct 
       add constraint FKjnj8ungt7v35y6lfxuxcrjbbr 
       foreign key (MEMBER_ID) 
       references Member
 
Hibernate: 
    
    alter table MemberProduct 
       add constraint FKrgt6jorh7iaec1tae84ljye8c 
       foreign key (PRODUCT_ID) 
       references Product
 
 
 

Entity 실행 결과

 

👉 기본 환경

- Language: Java

- DB: H2 Database

- IDE: IntelliJ

 

 

⌨️ 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import javax.persistence.*;
import java.util.List;
 
@Entity
public class Tmp {
 
    @Id @GeneratedValue
    @Column(name = "TMP_ID")
    private Long id;
 
    @OneToMany(mappedBy = "temp")
    private List<TmpItem> tmpItems;
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public List<TmpItem> getTmpItems() {
        return tmpItems;
    }
 
    public void setTmpItems(List<TmpItem> tmpItems) {
        this.tmpItems = tmpItems;
    }
}
 
 
 

 

 

🖨️오류

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Exception in thread "main" org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: jpabook.jpashop.domain.TmpItem.temp in jpabook.jpashop.domain.Tmp.tmpItems
    at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:844)
    at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:795)
    at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:53)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1693)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1661)
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:286)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1214)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1245)
    at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:56)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
    at jpabook.jpashop.JpaMain.main(JpaMain.java:15)
 
 
 

 

 

📡 원인

@OneToMany에서 매핑되는 TmpItem Entity에서 참조할 필드가 없음

 

 

📰 해결 방법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import javax.persistence.*;
import java.util.List;
 
@Entity
public class Tmp {
 
    @Id @GeneratedValue
    @Column(name = "TMP_ID")
    private Long id;
 
    @OneToMany(mappedBy = "tmp")
    private List<TmpItem> tmpItems;
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public List<TmpItem> getTmpItems() {
        return tmpItems;
    }
 
    public void setTmpItems(List<TmpItem> tmpItems) {
        this.tmpItems = tmpItems;
    }
}
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import javax.persistence.*;
 
@Entity
public class TmpItem {
 
    @Id
    @GeneratedValue
    @Column(name = "TMP_ITEM_ID")
    private Long id;
 
    @ManyToOne
    @JoinColumn(name = "TMP_ID")
    private Tmp tmp;
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public Tmp getTmp() {
        return tmp;
    }
 
    public void setTmp(Tmp tmp) {
        this.tmp = tmp;
    }
}
 
 
 

 

TmpItem Entity에 매핑된 필드와 동일한 이름으로 변경

     - @OneToMany(mappedBy = "temp") ▶ @OneToMany(mappedBy = "tmp")

 

👉 기본 환경

- Language: Java

- DB: H2 Database

- IDE: IntelliJ

 

 

⌨️ 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import javax.persistence.*;
import java.util.List;
 
@Entity
public class Tmp {
 
    @GeneratedValue
    @Column(name = "TMP_ID")
    private Long id;
 
    @OneToMany(mappedBy = "tmp")
    private List<TmpItem> tmpItems;
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public List<TmpItem> getTmpItems() {
        return tmpItems;
    }
 
    public void setTmpItems(List<TmpItem> tmpItems) {
        this.tmpItems = tmpItems;
    }
}
 
 
 

 

 

🖨️오류

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Exception in thread "main" org.hibernate.AnnotationException: No identifier specified for entity: jpabook.jpashop.domain.Tmp
    at org.hibernate.cfg.InheritanceState.determineDefaultAccessType(InheritanceState.java:266)
    at org.hibernate.cfg.InheritanceState.getElementsToProcess(InheritanceState.java:211)
    at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:781)
    at org.hibernate.boot.model.source.internal.annotations.AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(AnnotationMetadataSourceProcessorImpl.java:254)
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess$1.processEntityHierarchies(MetadataBuildingProcess.java:230)
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:273)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1214)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1245)
    at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:56)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
    at jpabook.jpashop.JpaMain.main(JpaMain.java:15)
 
 
 

 

 

📡 원인

Entity 선언 시, 필수적으로 @Id를 통해서 PK 1개 이상 지정해야 함

⭐ 데이터베이스 무결성 - 키 무결성

    - [CS] Database

 

 

📰 해결 방법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import javax.persistence.*;
import java.util.List;
 
@Entity
public class Tmp {
 
    @Id @GeneratedValue
    @Column(name = "TMP_ID")
    private Long id;
 
    @OneToMany(mappedBy = "tmp")
    private List<TmpItem> tmpItems;
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public List<TmpItem> getTmpItems() {
        return tmpItems;
    }
 
    public void setTmpItems(List<TmpItem> tmpItems) {
        this.tmpItems = tmpItems;
    }
}
 
 
 

PK에 @Id 추가

 

👉 기본 환경

- Language: Java

- DB: H2 Database

- IDE: IntelliJ

 

 

⌨️ 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import javax.persistence.*;
import java.util.List;
 
public class Tmp {
 
    @Id @GeneratedValue
    @Column(name = "TMP_ID")
    private Long id;
 
    @OneToMany(mappedBy = "tmp")
    private List<TmpItem> tmpItems;
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public List<TmpItem> getTmpItems() {
        return tmpItems;
    }
 
    public void setTmpItems(List<TmpItem> tmpItems) {
        this.tmpItems = tmpItems;
    }
}
 
 
 

 

 

🖨️오류

1
2
3
4
5
6
7
8
9
10
11
12
13
Exception in thread "main" org.hibernate.AnnotationException: @OneToOne or @ManyToOne on jpabook.jpashop.domain.TmpItem.tmp references an unknown entity: jpabook.jpashop.domain.Tmp
    at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:97)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processEndOfQueue(InFlightMetadataCollectorImpl.java:1823)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processFkSecondPassesInOrder(InFlightMetadataCollectorImpl.java:1767)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1655)
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:286)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1214)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1245)
    at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:56)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
    at jpabook.jpashop.JpaMain.main(JpaMain.java:15)
 
 
 

 

 

📡 원인

Entity 클래스 선언 시, @Entity 선언을 하지 않아 인식되지 않음

그에 따라 Entity간 매핑해놓은 @ManyToOne에서 unknown entity exception 발생

 

 

📰 해결 방법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import javax.persistence.*;
import java.util.List;
 
@Entity
public class Tmp {
 
    @Id @GeneratedValue
    @Column(name = "TMP_ID")
    private Long id;
 
    @OneToMany(mappedBy = "tmp")
    private List<TmpItem> tmpItems;
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public List<TmpItem> getTmpItems() {
        return tmpItems;
    }
 
    public void setTmpItems(List<TmpItem> tmpItems) {
        this.tmpItems = tmpItems;
    }
}
 
 
 

Entity 클래스에 @Entity 추가

 

이 글은 김영한의 [자바 ORM 표준 JPA 프로그래밍 - 기본편] 수강하며 정리한 글입니다.

 

👉 기본 환경

- Language: Java

- DB: H2 Database

- IDE: IntelliJ

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
@Entity
public class Member {
 
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
    private String name;
    private String city;
    private String street;
    private String zipcode;
 
    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getCity() {
        return city;
    }
 
    public void setCity(String city) {
        this.city = city;
    }
 
    public String getStreet() {
        return street;
    }
 
    public void setStreet(String street) {
        this.street = street;
    }
 
    public String getZipcode() {
        return zipcode;
    }
 
    public void setZipcode(String zipcode) {
        this.zipcode = zipcode;
    }
 
}
 
 
 

Member : Order = 1 : 다

 

1명의 사용자가 여러개의 주문을 할 수 있으므로 Order는 List로 저장

 

private List<Order> orders; 가 아닌 private List<Order> orders = new ArrayList<>(); 이유

    - private List<Order> orders는 기본적으로 null값을 갖게 됨

    - 초기화를 하지 않고 orders에 대한 연산 실행 시, NullPointerException이 발생할 수 있음

    - 그러므로 Entity에서 초기화하여 NullPonterException 방지