본문 바로가기
BackEnd/JPA

[JPA] 스프링 데이터 JPA 이야기 2부 - JPA 사용법

by 뽀뽀이v 2020. 9. 23.

이 글은 백기선 님의 스프링 데이터 JPA 강의를 듣고 복습 차원에서 적은 글입니다.

이 글은 김영한 님의 자바 ORM 표준 JPA 프로그래밍 책을 읽고 복습 차원에서 적은 글입니다.

 

스프링 부트를 기반으로 환경설정을 했다.

JPA는 엔티티와 테이블을 매핑하고 DB 스키마를 자동으로 생성한다.

ddl_auto 옵션으로 로컬에서 편하게 스키마를 만들 수 있다.

 

applicaton.properties

spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true

JpaRunner.class

@Component
@Transactional
public class JpaRunner implements ApplicationRunner {

    @PersistenceContext
    EntityManager entityManager;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 회원 엔티티
        Member member = new Member();
        member.setUsername("giuly");
        member.setPassword("1026");

        // 강좌 엔티티
        Course course = new Course();
        course.setName("Spring Data JPA");
        course.setMember(member);

        // 관계의 주인은 Course 이다.
//        member.getCourses().add(course);
//        course.setMember(member);
        member.addCourses(course);

        // entityManager.persist(member);
        Session session = entityManager.unwrap(Session.class);
        session.save(member);
        session.save(course);
}

Member.class

@Entity
// @Entity(name = "myMember") -> 객체의 이름을 따로 설정할 수 있다.
// @Table => 테이블 이름을 설정할 수 있다. Entity 객체의 이름이 디폴트 값이다.
public class Member {

    @Id // PK
    @GeneratedValue // 자동증가
    private Long id; // Long vs long 차이가 있다. -> https://siyoon210.tistory.com/139

    // @Column -> @Entity 생략 가능
    // @Column(nullable = false, unique = true)
    private String username;

    private String password;

    // TemporalType.Date : 년-월-일 의 date 타입
    // TemporalType.Time : 시:분:초 의 time 타입
    // TemporalType.TIMESTAMP : date + time 의 timestamp(datetime) 타입
    @Temporal(TemporalType.TIMESTAMP)
    private Date createDate = new Date();

    // @Transient -> 테이블 컬럼으로는 사용하고 싶지 않을 때 사용한다.
    @Transient
    private String test;

    @Embedded
//    @AttributeOverrides({
//        @AttributeOverride(name = "street", column = @Column(name = "home_street"))
//    })
    private Address address;

//    @OneToMany // 단방향 상태이다.
//    private Set<Course> courses = new HashSet<Course>();

    @OneToMany(mappedBy = "member") // 양방향 상태이다.
    private Set<Course> courses = new HashSet<Course>();

    // Companion Method
    public void addCourses(Course course) {
        this.getCourses().add(course);
        course.setMember(this);
    }

    public void removeCourses(Course course) {
        this.getCourses().remove(course);
        course.setMember(null);
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    public String getTest() {
        return test;
    }

    public void setTest(String test) {
        this.test = test;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public Set<Course> getCourses() {
        return courses;
    }

    public void setCourses(Set<Course> courses) {
        this.courses = courses;
    }

}

Course.class

@Entity
public class Course {

    @Id @GeneratedValue
    private Long id;

    private String name;

    // Many => One
    @ManyToOne // FK
    private Member member;

    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 Member getMember() {
        return member;
    }

    public void setMember(Member member) {
        this.member = member;
    }

}

Address.class

@Embeddable
public class Address {

    private String street;

    private String city;

    private String state;

    private String zipCode;
    
}

JPA 프로그래밍 : 엔티티 맵핑 

@Entity

  • 엔티티란 객체 세상에서 부르는 이름이다.
  • 보통 클래스와 같은 이름을 사용한다.
  • 엔티티의 이름은 JPAL에서 사용한다.

@Table

  • 릴레이션 세상에서 부르는 이름이다.
  • @Entity의 이름이 기본값이다.
  • 테이블 이름은 SQL에서 사용한다.

@Id

  • 엔티티의 주키를 매핑할 때 사용한다.

@GeneratedValue

  • 주키의 생성 전략과 생성기를 설정할 수 있다.

@Column

  • 컬럼을 제약조건과 타입 등을 설정할 수 있다.

@Temporal

  • 현재 JPA2.1까지는 Date와 Calendar만 지원한다.

@Transient

  • 컬럼으로 매핑하고 싶은 않은 멤버 변수에 사용한다.

JPA 프로그래밍 : Value 타입 맵핑

Value 타입의 종료는 3가지가 있다.

1. 기본값 타입

  • 자바 기본 타입 (int, double)
  • 래퍼 클래스 (Integer, Long)
  • String

2. 임베디드 타입

  • JPA에서 정의해서 사용해야 한다. (@Embeddable, @Embedded, @QAttributeOverrides, @AttributeOverride)

3. 컬렉션 값 타입

  • JPA에서 정의해서 사용해야 한다.
  • 컬렉션에 기본값 또는 임베디드 타입을 넣은 형태이다.

JPA 프로그래밍 : 1대다 맵핑

관계에는 항상 두 엔티티가 존재한다. 둘 중 하나는 그 관계의 주인이고, 다른 쪽은 종속된 부분이다.

단방향

  • @ManyToOne (기본값은 FK를 생성한다.)
  • @OneToMay (기본값은 조인 테이블을 생성한다.)
Hibernate: 
insert into member
(city, state, street, zip_code, create_date, password, username, id) 
values (?, ?, ?, ?, ?, ?, ?, ?)

Hibernate: 
insert into course (member_id, name, id) 
values (?, ?, ?)
Hibernate: 
insert into member_courses
(member_id, courses_id) 
values (?, ?)


 Schema |      Name      | Type  |   Owner
--------+----------------+-------+------------
 public | course         | table | jihuni1026
 public | member         | table | jihuni1026
 public | member_courses | table | jihuni1026

자동으로 member_courses라는 관계 테이블을 만들어 준다.

양방향

  • @ManyToOne 내가 주인이다.
  • @OneToMany(mappedBy) 주인한테 관계를 설정해야 DB에 반영된다.
Hibernate: 
insert into member
(city, state, street, zip_code, create_date, password, username, id) 
values (?, ?, ?, ?, ?, ?, ?, ?)

Hibernate: 
insert into course
(member_id, name, id) 
values (?, ?, ?)


 Schema |  Name  | Type  |   Owner
--------+--------+-------+------------
 public | course | table | jihuni1026
 public | member | table | jihuni1026

단방향은 실제 테이블을 3개 운영해야 되기 때문에 양방향을 추천한다.

여기서는 JPA 사용법을 배웠습니다.

핵심만 정리하자면 JPA는 @Entitiy를 분석해서 자동으로 DB에 테이블을 생성한다.

엔티티 Value타입에는 기본값, 임베디드, 컬렉션 3가지가 있다.

맵핑에는 단방향과 양방향이 있다. 

정도만 아시면 되겠습니다.

댓글