영속성 컨텍스트
영속성 컨텍스트
- 엔티티를 영구 저장하는 환경
-
EntityManager.persist(Entity)

엔티티의 생명주기
- 비영속
- jpa와 상관이 없는 상태
Member member = new Member(); member.setName("member1"); member.setAge(20); - 영속
- 객체가 EntityManager에 의해 관리되는 상태
EntityManeger.persist(member);
- 객체가 EntityManager에 의해 관리되는 상태
- 준영속
- 객체와 영속성 컨텍스트를 분리
- detech(), clear(), close() 사용
- 삭제
- 객체를 삭제
- remove() 사용
영속성 컨텍스트의 이점
-
1차 캐시
em.persist(member); //1차캐시에 저장 em.find(Member.class,member.getId); //1차 캐시에서 조회 -
동일성 보장
Member member1 = em.find(Member.class,"id1"); Member member2 = em.find(Member.class,"id1"); member1 == member2 // true - 쓰기 지연
transaction.begin(); em.persist(Member1); em.persist(Member2); transaction.commit(); //이때 db에 저장된다. -
변경감지
transaction.begin(); Member member = em.find(Member.class,"memberA"); member.setName("newName"); transaction.commit();
- 비영속
엔티티 매핑
엔티티 클래스 생성
- @Entity : Jpa가 관리할 객체
- @Table : 매핑할 테이블을 지정
- @Id : db의 pk와 매핑할 필드
- @GeneratedValue : 기본키 생성방법을 지정
- IDENTITY - 데이터 베이스에 지정 ex) Auto_Increment
- SEQUENCE - 데이터베이스 오브젝트 스퀀스 사용
- TABLE - 키 생성용 테이블 사용
- AUTO - 방언에 따라 지정
- @Column : 필드와 컬럼을 매핑
- @Column(name = “username”)
- @Enumerated : enum타입과 매핑
- @Lob : Blob, Clob 와 매핑
- @@Temporal : 날짜 타입을 매핑하고 싶을떄 사용
-
@Transient : 해당 컬럼은 매핑하지 않는다.
@Entity @Table(name = "member") public class Member{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "username") private String name; @Enumerated(EnumType.STRING) private UserState state; ... }
연관관계 매핑
단방향 연관 관계

- 객체의 참조와 테이블의 외래키를 매핑한다.
- 하나의 팀에는 다수의 멤버가 소속될수 있다.
- 두 엔티티의 연관관계는 팀의 입장에서 볼때는 일대다(@OneToMany) ,멤버의 입장에서 볼때는 다대일(@ManyToOne)의 관계이다.
@Entity
public class Member{
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
}
연관관계 사용 방법
//팀 저장
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Memeber();
member.setName("member1");
member.setTeam(team); //단방향 연관관계 설정, 참조 저장
em.persist(member);
em.find(Member.class,member.getId); //한번에 조인해서 team과 member를 가져온다. fetch lazy로 수정 권장
연관관계 수정
//새로운 팀B
Team teamB = new Team();
team.setName("TeamB");
em.persist(teamB);
member.setTeam(teamB);
양방향 연관 관계

- 테이블 상에서는 바뀌는 것이 없다 .
- Team에서는 members를 가지고있고 member는 team을 가지도록 설계하면 된다.
@Entity
public class Team{
@Id
@generatedValue
private Long Id;
private String name;
@OneToMany(MappedBy = "team") //team과 연관이 있다는것 명시
private List<Member> members = new ArrayList<Member>();
}
Team findTeam = em.find(Team.class,teamA.getId);
int memSize = findTeam.getMembers.size();
연관관계의 주인
양방향 연관관계의 패러다임
member.team으로 Fk를 관리해야 할까? 아니면 team.members로 외래키를 관리해야 할까?
-> Fk를 가진쪽을 연관관계의 주인으로 해야한다. 즉 Member.team이 Fk이므로 Member쪽이 연관관계의 주인이다.
주인은 joinColumn을 사용하고 주인이 아니면 mappedBy를 사용해서 속성으로 주인을 지정한다.
연관관계의 주인이 아닌쪽은 조회만 가능 하도록 한다.
연관관계에서 주의 할 점
-
연관관계의 주인에 값을 입력해야한다.
Team team = new Team(); team.setName("TeamA"); em.persist(team); Member member = new Member(); member.setName("member1"); em.persist(member); //이부분을 추가하지 않으면 Fk에 값이 들어가지 않는다. //member.setTeam(team);|ID|USERNAME|TEAM_ID| |:———-|:———-:|———-:| |1|member1|null|
-
toString 사용 시 무한 루프에 빠질수 있으므로 사용하지 않는것을 권장
다양한 연관관계 매핑
다대일

- 테이블에서 외래키는 항상 다 쪽에 있다.
- 가장 다중적인 매핑
다대일 단방향 매핑
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
다대일 양방향 매핑
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
엔티티 저장
Team team = new Team();
team.setName("A");
em.persist(team);
System.out.println("-----팀 저장");
Member member = new Member();
member.setUsername("NJ");
member.changeTeam(team);
em.persist(member);
System.out.println("-----멤버 저장");
tx.commit();
결과
Hibernate:
/* insert hello.jpa.Team
*/
insert
into
Team
(id, name)
values
(null, ?)
-----팀 저장
Hibernate:
/* insert hello.jpa.Member
*/
insert
into
Member
(id, age, createdDate, description, lastModifiedDate, roleType, TEAM_ID, name)
values
(null, ?, ?, ?, ?, ?, ?, ?)
-----멤버 저장
일대다
일대다 단방향 매핑

- 실무에서는 권장하지 않는다.
- 일대다에서 일이 연관관계의 주인
- 객체와 테이블의 차이때문에 반대편테이블의 외래키를 관리하는 구조
- @joinColum을 사용하지 않으면 새로운 테이블이 생성된다.
//Team
@OneToMany
@JoinColumn(name = "TEAM_ID")
private List<Member> members = new ArrayList<Member>();
//Member
//Team 없앰
실행문
Member member = new Member();
member.setUsername("NJ");
em.persist(member);
System.out.println("-----멤버 저장");
Team team = new Team();
team.setName("A");
team.getMembers().add(member);
em.persist(team);
System.out.println("-----팀 저장");
tx.commit();
결과
Hibernate:
/* insert hello.jpa.Member
*/
insert
into
Member
(id, age, createdDate, description, lastModifiedDate, roleType, name)
values
(null, ?, ?, ?, ?, ?, ?)
-----멤버 저장
Hibernate:
/* insert hello.jpa.Team
*/
insert
into
Team
(id, name)
values
(null, ?)
-----팀 저장
Hibernate:
/* create one-to-many row hello.jpa.Team.members */
update
Member
set
TEAM_ID=?
where
id=?
일대다 양방행 매핑
-지원하지 않는다.