GitHub 자세히보기

Programming/JAVA

[Spring] JPA , ORM 개념과 연관관계 매핑 알아보기

devdange 2022. 1. 13. 01:42

들어가며

지금까지 MyBatis만 사용하다가 이번 프로젝트에서 JPA를 사용하게 되었습니다. 현업에서도 많이 사용하고 있으며, 진입장벽(?!)은 높지만 한번 익히고 나면 SQL에 의존적이지 않고 객체 의존적인 코드를 구현할 수 있을 것 같다는 생각을 했습니다. 프로젝트에 앞서 간단하게 JPA에 대해 알아보는 시간을 갖겠습니다. 

 

JPA(Java Persistence API) 란?

자바 플랫폼 SE와 자바 플랫폼 EE를 사용하는 응용프로그램에서 관계형 데이터베이스의 관리를 표현하는 자바 API입니다. 자바 진영의 ORM 기술 표준이며, 인터페이스의 모음이라고 볼 수 있다.

발전과정 
EJB- 엔티티 빈(자바표준) ➔ 하이버네이트(오픈소스) ➔ JPA(자바 표준) 

 

JPA의 필요성

  • SQL 중심적인 개발에서 객체 중심으로 개발 가능
  • 생산성 증가
  • 유지보수 용이
  • 패러다임의 불일치 해결
  • 성능 향상
  • 데이터 접근 추상화와 벤더 독립성

 

ORM이란?

  • Objected-Relational Mapping(객체 관계 매핑)
  • 객체는 객체대로 설계
  • 관계형 데이터베이스는 관계형 데이터베이스대로 설계
  • ORM 프레임워크가 중간에서 매핑
  • 대중적인 언어에는 대부분 ORM 기술이 존재

 

기본 매핑

  • 스키마 자동 생성 옵션 지정 
    • create : 기존 테이블 삭제 후 다시 생성(DROP+CREATE)
    • create-drop : create와 같으나 종료시점에 테이블 DROP
    • update : 변경분만 반영
    • validate : 엔티티와 테이블이 정상 매핑되었는지만 확인
    • none : 사용하지 않음

 

  • 객체 매핑하기
    • @Entity : JPA가 관리할 객체
    • @Id : DB PK와 매핑할 필드 
      @Entity
        public class User{
          @Id
          String userId;
          String name;
      }​


  • 매핑 어노테이션(DB에 매핑되는 정보)
    • @Column
      • 컬럼 관련 어노테이션으로 가장 많이 사용됨
      • name : 필드와 매핑할 테이블의 컬럼 이름
      • insertable, updatable : 읽기 전용
      • nullable : 허용여부 결정, DDL 생성시 사용
      • unique : 유니크 제약 조건, DDL 생성시 사용
        @Column(nullable = false) // not null
        String name;
        @Column(name="user_id") // table에 "user_id"로 컬럼생성
        String userId;​
    • @Temporal 
      • 날짜 타입 매핑
        @Temporal(TemporalType.DATE)
        Date date;  //날짜
        @Temporal(TemporalType.TIME)
        Date time;  //시간
        @Temporal(TemporalType.TIMESTAMP)
        Date timeStamp; //날짜와 시간
      • @Enumerated : 열거형 매핑
      • @Lob : 컨텐츠 길이가 길때 byte로 저장
      • @Transient
        • 이 필드는 매핑하지 않는다.
        • 애플리케이션에서 DB에 저장하지 않는 필드

 

  • 식별자 매핑 어노테이션
    • @Id : 직접매핑
    • @GeneratedValue
      • IDENTITY : 데이터베이스에 위임. MySQL
      • SEQUENCE : 데이터베이스 시퀀스 오브젝트 사용. Oracle
        • @SequenceGenerator 필요
      • TABLE :  키생성용 테이블 사용
        • @TableGenerator 필요
      • AUTO : 방언에 따라 자동지정, 기본값
        //import javax.persistence.Id;
        @Id // Table DB PK와 매핑할 필드
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        Long id = null;​


연관관계 매핑

  • 단방향 매핑
    @Entity
    public class UserConference{
        int conferenceId;
        //int userId; // JoinColumn 컬럼에서 작성되기 때문에 삭제
        // 연관관계작성
        @ManyToOne(fetch = FetchType.LAZY) // 조인된 객체가 아닌 단일 객체만 가져오기
        //@ManyToOne(fetch = FetchType.EAGER) // default -> 조인된 값을 가져옴
        @JoinColumn(name="user_id")
        User user;
    }​
     

 

  •  양방향 매핑
    • 반대방향으로 객체 그래프   
      // 위에 작성한 단방향 코드도 작성되어야함
      @Entity
      public class User{
          String department;
          String position;
          String name;
          String userId;
          @OneToMany(mappedBy = "user")
          List<UserConference> userConferences = new ArrayList<UserConference>();
      }​

 

  • 양방향 매핑의 장점
    • 단방향 매핑만으로도 이미 연관관계 매핑은 완료
    • 양방향 매핑은 반대방향으로 조회(객체 그래프 탐색) 기능이 추가된 것 뿐
    • 단방향 매핑을 잘하고 양방향은 필요시 추가하면 됨(테이블에 영향을 주지않음)

 

  • 연관관계 매핑 어노테이션
    • 다른 어노테이션은 제약조건이 많기 때문에 현업에선 아래 두 가지를 많이 사용
      • 다대일(@ManyToOne)
      • 일대다(@OneToMany

 

마무리

쉬운 듯 하지만 생각보다 복잡한 관계를 가지고 있는 JPA를 충분히 이해하고 사용하면 개발의 효율을 증대시킬 수 있을 것 같습니다. 다만 연관 매핑 시, 어느 객체를 중심으로 JoinColumn을 지정할지 충분한 고민이 필요할 것 같습니다.