3 minute read

영속성 컨텍스트



  • 엔티티를 영구 저장하는 환경
  • EntityManager.persist(Entity)

    영속성컨텍스트

    엔티티의 생명주기

    1. 비영속
      • jpa와 상관이 없는 상태
         Member member = new Member();
         member.setName("member1");
         member.setAge(20);
      
    2. 영속
      • 객체가 EntityManager에 의해 관리되는 상태
              EntityManeger.persist(member);
        
    3. 준영속
      • 객체와 영속성 컨텍스트를 분리
      • detech(), clear(), close() 사용
    4. 삭제
      • 객체를 삭제
      • remove() 사용


      영속성 컨텍스트의 이점

    5. 1차 캐시

      영속성컨텍스트

       em.persist(member); //1차캐시에 저장
       em.find(Member.class,member.getId);  //1차 캐시에서 조회
      
    6. 동일성 보장

       Member member1 = em.find(Member.class,"id1");
       Member member2 = em.find(Member.class,"id1");
      
       member1 == member2 // true
      
    7. 쓰기 지연
       transaction.begin();
      
       em.persist(Member1);
       em.persist(Member2);
      
       transaction.commit(); //이때 db에 저장된다.
      
    8. 변경감지

       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를 사용해서 속성으로 주인을 지정한다.

연관관계의 주인이 아닌쪽은 조회만 가능 하도록 한다.


연관관계에서 주의 할 점

  1. 연관관계의 주인에 값을 입력해야한다.

     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|

  2. toString 사용 시 무한 루프에 빠질수 있으므로 사용하지 않는것을 권장

다양한 연관관계 매핑


다대일

단방향 연관관계

  1. 테이블에서 외래키는 항상 다 쪽에 있다.
  2. 가장 다중적인 매핑

다대일 단방향 매핑

   @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=?

일대다 양방행 매핑

-지원하지 않는다.

Categories:

Updated: