ORM과 JPA
ORM이라는 것은 Java(다른 언어 등) Object를 테이블로 매핑해주는 기술이다.
즉, 내가 오브젝트를 만들면 테이블로 만들어주는 것이다.
JPA는 ORM을 사용하기 위한 인터페이스를 모아둔 것이다.
JPA를 사용하기 위해서는 JPA를 구현한 Hibernate, EclipseLink, DataNucleus 같은
ORM 프레임워크를 사용해야 한다.
User 테이블 생성
우선 com.cos.blog.model 패키지를 만들고 Board, Reply, User 클래스들을 생성한다.
User 클래스를 먼저 살펴보자
일단 모든 테이블에는 primary key가 필요하기 때문에 primary key 부터 정의한다.
MySQL에서 auto_increment로 넘버링한다.
이렇게 작성했는데, 이 클래스를 테이블화 시키기 위해서는 @Entity라는 어노테이션을 붙여주면 된다.
그리고 id를 Primary key로 설정하기 위해 @Id를 붙여주고,
프로젝트에 연결된 DB의 넘버링 전략을 따라가기 위해 @GeneratedValue ... 를 붙여준다.
application.yml에서 이 코드는 jpa가 사용하는 기본 넘버링 전략을 사용하지 않겠다는 것이다.
즉, 이 프로젝트는 jpa가 사용하는 기본 넘버링 전략을 따라가지 않고 연결된 DB의 넘버링 전략을 따라간다.
그리고 유저의 아이디, 비밀번호, 이메일, 가입일자를 다음과 같이 설정한다.
여기다가 다음 코드를 추가한다.
@ColumnDefault는 기본값을 설정하는 것인데 (" 'user' ") 이렇게 되어있는 것이다. user로 기본값을 설정한다.
마지막으로 getter setter와 생성자와 빌더 패턴을 만들어준다.
User.java
package com.cos.blog.model;
import java.sql.Timestamp;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.CreationTimestamp;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder // 빌더 패턴
@Entity // User 클래스가 MySQL에 테이블이 생성된다.
public class User {
@Id // Primary key
@GeneratedValue(strategy = GenerationType.IDENTITY)
// 프로젝트에서 연결된 DB의 넘버링 전략을 따라간다. 즉, MySQL일 경우 auto_increment를 사용한다는 것이다.
private int id; // 시퀀스(오라클), auto_increment로 넘버링(MySQL)
@Column(nullable = false, length = 30) // null이 될 수 없고, 30자 이상이 될 수 없다.
private String username; // 아이디
@Column(nullable = false, length = 100) // 비밀번호 암호화한 해쉬 넣어볼 예정이므로 길게 설정
private String password;
@Column(nullable = false, length = 50)
private String email;
@ColumnDefault("'user'")
private String role;
// admin, user, manager ...
// 정확히는 Enum을 사용하는 것이 좋다. Enum을 사용하면 어떤 데이터의 도메인(범위)을 만들 수 있다.
// role이 String이므로 adminn과 같은 오타를 낼 수가 있다. Enum을 사용하면 이를 방지할 수 있다.
@CreationTimestamp // 데이터가 insert나 update 될 때 시간이 자동으로 입력된다.
private Timestamp createDate;
}
application.yml에서 이 코드는 테이블을 새로 생성하겠다는 것이다.
만약 기존에 User라는 테이블이 있어도 실행할 때 마다 새로 만들게 된다.
그래서 최초에는 이렇게 create라고 설정하고, 테이블을 생성하게 되면
이렇게 update로 바꿔놔야 한다.
그래야 테이블을 새로 만들지 않고, 기존의 데이터에 추가해서 데이터가 DB에 들어가게 된다.
이제 실행을 해보자
실행하기 전에 MySQL이 동작하고 있는지 ctrl+alt+delete를 눌러 작업관리자를 켜 확인해보자
MySQL이 실행중인 것을 확인했다.
실행을 해보면
콘솔에 이렇게 테이블이 생성된 것을 확인할 수 있다.
현재 ddl-auto: create 이라서 기존에 User 테이블이 있다면 삭제해버리고 새로 생성하게 된다.
이렇게 콘솔창에서 테이블을 확인할 수 있는 이유는
이렇게 show-sql: true 로 설정되어 있기 때문이다.
그런데 만약 show-sql: true 만 설정되어 있다면 한줄로 다 출력되는데,
이 코드를 작성하면 코드가 정렬되서 깔끔하게 출력된다.
이 코드는 @Entity로 테이블을 생성할 때 변수명 그대로 데이터베이스에 필드로 넣는다는 것이다.
변수명인 id, username, password, email이 그대로 테이블 필드를 만든다는 것이다.
이제 MySQL Workbench에서 확인해보면
제대로 테이블이 생성되어 있는 것을 확인할 수 있다.
'email'에서 'em'으로 바꾸면 다시 쿼리가 실행되고 em으로 바뀐다.
Board 테이블 생성
Board.java
package com.cos.blog.model;
import java.sql.Timestamp;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.CreationTimestamp;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // auto_increment
private int id;
@Column(nullable = false, length = 100)
private String title;
@Lob // 대용량 데이터
private String content; // 섬머노트 라이브러리 <html> 태그가 섞여서 디자인이 된다.
@ColumnDefault("0") // int 니까 ' ' 없이 숫자만 입력한다.
private int count; // 조회수
//private int userId; // ORM에서는 이 방식을 사용하지 않는다.
@ManyToOne // 연관관계를 맺어줘야 한다. Many=Board, User=One
@JoinColumn(name="userId")
// 실제로 데이터베이스에 만들어질 때는 userId라는 이름으로 만들어진다.
// 즉 테이블에 userId라는 필드값이 들어가게 된다.
private User user;
// DB는 오브젝트를 저장할 수 없다. FK, 자바는 오브젝트를 저장할 수 있다.
// 자바 프로그램에서 데이터베이스의 자료형에 맞춰 테이블을 만들게 된다.
// ORM을 사용하면 User user와 같이 오브젝트를 그대로 저장할 수 있다.
// 그런데 이렇게 만들면 테이블이 어떻게 인식할까?
// User 객체니 User.java 참조하고 Board.java에서 FK로 만들어 테이블에 저장한다.
// 데이터베이스에 오브젝트를 저장할 수 없기 때문이다.
@CreationTimestamp
private Timestamp createDate;
}
실행결과 :
Board 테이블도 제대로 생성된 것을 확인할 수 있다.
Reply 테이블 생성
Reply.java
package com.cos.blog.model;
import java.sql.Timestamp;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import org.hibernate.annotations.CreationTimestamp;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class Reply {
@Id // Primary key
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(nullable = false, length = 200)
private String content;
@ManyToOne //하나의 게시글에 여러 개의 덧글, OneToOne은 1:1
@JoinColumn(name="boardId")
private Board board; // 알아서 Board 테이블이랑 연결된다.
@ManyToOne
@JoinColumn(name="userId")
private User user;
@CreationTimestamp
private Timestamp createDate;
}
실행결과 :
MySQL Benchwork에서 reply 테이블이 제대로 생성된 것을 확인할 수 있다.
참고자료 :
'자바 스프링 > 부트 블로그 JPA 프로젝트' 카테고리의 다른 글
#11 insert 테스트와 enum 사용법 (1) | 2022.05.06 |
---|---|
#10 연관관계에 대한 이해 (0) | 2022.05.05 |
#8 스프링 부트의 yml과 jsp파일 리턴 (0) | 2022.05.04 |
#7 lombok 설치와 사용 (0) | 2022.05.04 |
#6 http요청 개념 및 실습 (0) | 2022.05.02 |