Spring/JPA

필드와 컬럼 매핑

느리지만 꾸준하게 2022. 4. 14. 04:52

요구사항을 추가시켜보면

  • 회원은 일반 회원과 관리자로 구분
  • 회원 가입일과 수정일이 있어야 함
  • 회원을 설명할 수 있는 필드가 있어야 함 / 필드는 길이 제한이 없다.

 

member class를 아래로 놓고

package hellojpa;

import javax.persistence.*;

import java.util.Date;

@Entity
public class Member {

    @Id
    private Long id;
    
    
    // 객체는 username으로 테이블은 name으로
    @Column(name = "name")
    private String username;
    
    private Integer age;
    
    @Enumerated(EnumType.STRING)
    private RoleType roleType;
    
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;
    
    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModifiedDate;
    
    // db에 varchar보다 큰 걸 넣고 싶으면 Lob를 준다.
    @Lob
    private String description;
}

 

RoleType enum을 아래와 같이 해주고 빌드를 돌려주면

package hellojpa;

public enum RoleType {
    GUEST, USER, ADMIN
}

 

결과가 아래와 같이 나온다.

Hibernate: 
    
    create table Member (
       id bigint not null,
        age integer,
        createdDate timestamp,
        description clob, // clob은 문자타입 lob 의미
        lastModifiedDate timestamp,
        roleType varchar(255),
        name varchar(255),
        TEAM_ID bigint,
        primary key (id)
    )

 

@Transient를 넣어주고 실행을 해주면 temp가 없이 나온다. 즉 메모리에서만 쓰겠다는 뜻이다.

  • 필드 매핑을 안하고
  • 데이터베이스에 저장 , 조회 둘다 안하고
  • 메모리상에만 임시로 값을 보관하고 싶을 때 쓴다
  • @Transient 
  • private Integer temp;
@Entity
public class Member {
    @Id
    private Long id;
    
    @Column(name = "name")
    private String username;
    private Integer age;
    
    @Enumerated(EnumType.STRING)
    private RoleType roleType;
    
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;
    
    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModifiedDate;
    
    @Lob
    private String description;

    @Transient
    private int temp;

    public Member() {

    }
}
rnate: 
    
    create table Member (
       id bigint not null,
        age integer,
        createdDate timestamp,
        description clob,
        lastModifiedDate timestamp,
        roleType varchar(255),
        name varchar(255),
        TEAM_ID bigint,
        primary key (id)
    )

 

 

 

 

 

아래는 db에 updatable을 false로 지정을 해주어서 update를 하지 않는다.

import java.util.Date;
@Entity
public class Member {

    @Id
    private Long id;

    @Column(name = "name", updatable = false)
    private String username;
    private Integer age;

    @Enumerated(EnumType.STRING)
    private RoleType roleType;

    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;

    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModifiedDate;

    @Lob
    private String description;

    @Transient
    private int temp;

    public Member() {

    }
}

 

 

 

nullable 같은 경우는 기본이 true인데 false를 하게되면 not null 제약조건이 걸리게 된다.

@Entity
public class Member {

    @Id
    private Long id;

    @Column(name = "name", nullable = false)
    private String username;
    private Integer age;
    
    
// 아래코드는 위와 동일
Hibernate: 
    
    create table Member (
       id bigint not null,
        age integer,
        createdDate timestamp,
        description clob,
        lastModifiedDate timestamp,
        roleType varchar(255),
        name varchar(255) not null,
        TEAM_ID bigint,
        primary key (id)
    )

 

 

unique제약 조건은 entity위에다가 설정을 해주어서 이름까지 보이게 할 수 있다.

@Entity
@Table(uniqueConstraints = )
public class Member {

 

@columnDefinition을 아래같이 설정하고 빌드를 돌리면

@Entity
public class Member {

    @Id
    private Long id;

    @Column(name = "name", nullable = false, columnDefinition = "varchar(100) default 'EMPTY'")
    private String username;
    private Integer age;

 

db에 종속적인 옵션인 columnDefinition까지 같이 볼 수가 있다.

Hibernate: 
    
    create table Member (
       id bigint not null,
        age integer,
        createdDate timestamp,
        description clob,
        lastModifiedDate timestamp,
        roleType varchar(255),
        name varchar(100) default 'EMPTY' not null,
        TEAM_ID bigint,
        primary key (id)
    )

 

 

숫자가 엄청 큰 경우에는 precision, scale(DDL)같은 옵션을 쓰면 된다.

@Column()
private BigDecimal age;

 

 

 

@Enumerated

  • 자바 enum 타입을 매핑할 때 사용(ORDINAL은 사용하지 말자 / 기본값이 ORDINAL)

설정을 해주고 빌드를 돌리면

Member class

package hellojpa;

import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import java.util.Date;
@Entity
public class Member {

    @Id
    private Long id;

    @Column(name = "name", nullable = false)
    private String username;

    private int age;

    @Enumerated
    private RoleType roleType;

    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;

    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModifiedDate;

    @Lob
    private String description;

    @Transient
    private int temp;

    public Member() {

    }
}

 

JpaMain

package hellojpa;

import org.hibernate.Hibernate;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;

public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try {
            Member member = new Member();
            member.setId(1L);
            member.setUsername("A");
            member.setRoleType(RoleType.USER);

            em.persist(member);
            
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
//            e.printStackTrace();
        } finally {
            em.close();
        }
        emf.close();
    }
}

 

기본이 ORDINAL이고 ORDINAL은 integer type으로 생성을 해준다.

Hibernate: 
    
    create table Member (
       id bigint not null,
        age integer not null,
        createdDate timestamp,
        description clob,
        lastModifiedDate timestamp,
        roleType integer,
        name varchar(255) not null,
        TEAM_ID bigint,
        primary key (id)
    )

 

 

persistence.xml에서 hibernate.hbm22l.auto를 아래와 같이 설정해주고

<property name="hibernate.hbm2ddl.auto" value="update" />

 

JpaMain을 아래와 같이 해서 돌리면 h2 db에서 

select * from member을 돌리면 데이터 A B두개가 나오게 된다.

package hellojpa;

import org.hibernate.Hibernate;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;

public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try {
            Member member = new Member();
            member.setId(2L);
            member.setUsername("B");
            member.setRoleType(RoleType.ADMIN);

            em.persist(member);

            tx.commit();
        } catch (Exception e) {
            tx.rollback();
//            e.printStackTrace();
        } finally {
            em.close();
        }
        emf.close();
    }
}

 

RoleType에서는 아래와 같이 설정을 해주었는데

package hellojpa;

public enum RoleType {
    GUEST, USER, ADMIN
}

 

jpamain상에서 guest를 추가하고 돌릴때  h2 db에는 user admin guest순으로 쌓이기 때문에 위험해진다.

package hellojpa;

import org.hibernate.Hibernate;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;

public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try {
            Member member = new Member();
            member.setId(3L);
            member.setUsername("C");
            member.setRoleType(RoleType.GUEST);

            em.persist(member);

            tx.commit();
        } catch (Exception e) {
            tx.rollback();
//            e.printStackTrace();
        } finally {
            em.close();
        }
        emf.close();
    }
}

 

 

결론은 아래와 같이  STRING으로 쓰자.

    @Enumerated(EnumType.STRING)
    private RoleType roleType;

 

 

 

 

@Temporal

  • 날짜 타입(java.util.Data, java.util.Calendar)을 매핑할 때 사용
  • 참고 : LocalDate, LocalDateTime을 사용할 때 생략 가능(최신 하이버네이트 지원)

LocalDate, LocalDateTime을 각각 지정해서 돌리면 아래와 같이 나타난다.

package hellojpa;

import javax.persistence.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import java.util.Date;
@Entity
public class Member {

    @Id
    private Long id;

    @Column(name = "name", nullable = false)
    private String username;

    private int age;

    @Enumerated(EnumType.STRING)
    private RoleType roleType;

    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;

    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModifiedDate;

    private LocalDate testLocalDate;
    private LocalDateTime testLocalDateTime;

    @Lob
    private String description;

    @Transient
    private int temp;

    public Member() {

    }

    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 int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public RoleType getRoleType() {
        return roleType;
    }

    public void setRoleType(RoleType roleType) {
        this.roleType = roleType;
    }

    public Date getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(Date createdDate) {
        this.createdDate = createdDate;
    }

    public Date getLastModifiedDate() {
        return lastModifiedDate;
    }

    public void setLastModifiedDate(Date lastModifiedDate) {
        this.lastModifiedDate = lastModifiedDate;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public int getTemp() {
        return temp;
    }

    public void setTemp(int temp) {
        this.temp = temp;
    }
}
Hibernate: 
    
    create table Member (
       id bigint not null,
        age integer not null,
        createdDate timestamp,
        description clob,
        lastModifiedDate timestamp,
        roleType varchar(255),
        testLocalDate date,
        testLocalDateTime timestamp,
        name varchar(255) not null,
        TEAM_ID bigint,
        primary key (id)
    )

 

@Lob - 데이터베이서 BLOB, CLOB 타입과 매핑

  • @Lob에 지정할 수 있는 속성이 없고
  • 매핑하는 필드 타입이 문자면 CLOB 매핑, 나머지는  BLOB 매핑

 

  • CLOB: String, char[], java.sql.CLOB
  • BLOB: byte[], java.sql. BLOB

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<출처 김영한: 자바 ORM 표준 JPA 프로그래밍 - 기본편 >

https://www.inflearn.com/course/ORM-JPA-Basic/dashboard

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., - 강의 소개 | 인프런

www.inflearn.com