<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="0000"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/spring?serverTimezone=Asia/Seoul&useSSL=false"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
pom.xml파일 변경
java11 사용시 작성
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- MySQL 데이터베이스-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
객체가 지향하는 패러다임과 RDB가 지향하는 패러다임이 극심히 다르다.

*주의
~~<property name="hibernate.hbm2ddl.auto" value="create" />~~
이 pom.xml 안의 옵션 코드를 입력해야 ddl문이 날라가면서 create가 된다..


위와 같은 sql문이 실행된 엔티티들을 조인한 결과이다.
Hibernate:
/* insert hellojpa.Team
*/ insert
into
Team
(name, TEAM_ID)
values
(?, ?)
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(TEAM_ID, USERNAME, MEMBER_ID)
values
(?, ?, ?)
//데이터를 찾을 때 계속 JPA에게 물어봐야하는 문제가 있다
Member findMember = em.find(Member.class, member.getId());
Long findTeamId = findMember.getTeamId();
Team findTeam = em.find(Team.class, findTeamId);
(객체가 참조를 이용해 연관된 객체를 찾는것을 위 코드에서 확인할 수 있다.)
가장 중요하고 가장 기본이다.
member 클래스의 teamId를 team으로 바꾸고 연관관계를 설정하면 연관관계를 활용하여
연관된 테이블을 찾아 컬럼들을 바로 활용할 수 있다
Member.class
// @Column(name = "TEAM_ID")
// private Long teamId;
@ManyToOne //멤버 입장에서는 Many고 Team입장에서는 One이기 떄문이다.
@JoinColumn(name = "TEAM_ID")
private Team team;
JpaMain.class
Member findMember = em.find(Member.class, member.getId());
Team findTeam = findMember.getTeam();
System.out.println("findTeam.getName() = " + findTeam.getName());
실행된 sql문
findTeam.getName() = TeamA //변수 출력 성공
Hibernate:
/* insert hellojpa.Team
*/ insert
into
Team
(name, TEAM_ID)
values
(?, ?)
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(TEAM_ID, USERNAME, MEMBER_ID)
values
(?, ?, ?)


외래 키 값을 관리하기 위해 딜레마에 빠진다.
이를 해결하기 위해 연관관계의 주인을 설정한다.
양방향 매핑 규칙
Member.class
@ManyToOne //멤버 입장에서는 Many고 Team입장에서는 One이기 떄문이다.
@JoinColumn(name = "TEAM_ID")
private Team team;
Team.class
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
⇒ 주인이 team 이다. 따라서, 중요한 점은
team.getMembers하면 연관된 team을 조회하는 것은 되는데,
값을 변경(update, insert) 시에는 private Team team 만 참조한다.

소감: hibernate 발음하는 아기가 굉장히 귀엽다.
정답: Book이 n이 되고, 연관관계의 주인이 된다. Bookstore는 참조되는 pk를 갖고 있고
mappedBy가 사용되어 읽기만 가능한 상태라 아무리 Bookstore에 Book을 꽂아도 저장이나 수정 삭제가 되지 않는다.
mappedBy 시 FK가 생성되므로 이 시점부터 FK를 수정해야(관계의 주인) 데이터베이스가 수정됨을 명심해야 한다.
Bookstore.add(book 객체) 시에 연관관계의 주인인 book 객체의 bookstore를 수정하는 코드를 Bookstore의 add 메소드에 추가해야 한다.
⇒객체(Books List)에 단순히 집어 넣는게 아닌 관계형 데이터베이스(Book)에 데이터를 집어 넣어주는 행위를 한다.
public void add(Member member) {
member.setTeam(this); // RDB에 데이터추가
this.members.add(member); // 객체의 배열에 단순히 추가
}
Team.class
public class Team {
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
public void add(Member member) {
member.setTeam(this); // 이 코드 한 줄이 없으면 fk에 null이 뜬다.
this.members.add(member); // Team 객체에 멤버를 배열에 추가한다.
}
}
Member.class
package hellojpa;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
@Entity
@Getter @Setter
public class Member {
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
// @Column(name = "TEAM_ID")
// private Long teamId;
@ManyToOne //멤버 입장에서는 Many고 Team입장에서는 One이기 떄문이다.
@JoinColumn(name = "TEAM_ID")
private Team team;
}
JpaMain.class
try {
//저장
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setUsername("member2");
team.add(member); //새로 만든 팀 객체에 새로 만든 멤버를 추가하려고 한다.
em.persist(member);
em.flush();
em.clear();
List<Member> members = team.getMembers();
System.out.println("members = " + members); //Team 클래스의 배열 저장 코드가 없으면 null
tx.commit();
}
mappedBy가 없으면
@OneToMany
@ManyToOne
이 두개가 각각의 Book, BookStore 클래스에 존재하는데
이 경우 의미는 단방향 2개가 존재하는 상황이라는 의미다.
⇒ 스키마가 전혀 다르다. bookstore, books의 조인 테이블이 새로 생긴다.
mappedBy를 함으로써 양방향 관계가 되는 것이다.
⇒ 조인 테이블이 새로 생기지 않고 book(연관관계의 주인) 쪽에 FK가 생성된다.
단, 양방향 관계는 mappedBy만 쓰는 방법만 있는 것이 아니다.
강의와 내 코드가 달랐던 점.. JoinColumn의 생략
만약 @JoinColumn을 생략한다면, 외래 키를 찾을 때 다음 기본 전략을 사용합니다.
필드명_[참조하는 테이블의 기본 키 컬럼명]
@ManyToOne
private Team team;
Joincolumn의 name속성은 그저 member테이블의 조인컬럼의 컬럼명을 지정하는것뿐 team과 매핑하는것과는 관련이없다.
member와 team을 연관관계맺는것은 referencedColumnName속성이 하지만 이것을 생략하면 자동으로 team의 pk값으로 연관관계를 맺어줘서 생략한다.
@Getter, @Setter ⇒ 롬복 설치
Getter, Setter 애노테이션으로 긴 코드 대체 가능
JPA에서 가장 많이 사용하고 기초가 되는 다대일

일대다 단방향의 문제점
@JoinColumn(name = “연결될 컬럼명”, insertable = “false”, updatable=”false”)
⇒읽기 전용 매핑

한쪽에 mappedBy를 걸어주면 되서 다대일 양방향이랑 비슷하다.




실무에서 쓰면 안된다.

객체는 다대다가 된다


중간테이블이 숨겨져 있기 때문에 예측하지 못한 쿼리문이 나갈 수도 있다

이렇게 되면 중간테이블(Orders)에 원하는 필드를 맘껏 추가할 수 있다
ex) price, count…