본문 바로가기
백엔드

JPA란? (Spring Boot + JPA 환경설정 및 사용법)

by BeforB 2020. 3. 18.
728x90

JPA란?

Java Persistance API. 자바의 ORM(Object-Relational Mapping) 표준 기술이다. 즉 자바의 객체와 관계형 DB를 매핑하는 기술이다.

 

Hibernate

Hibernate란? ORM Framework 중 하나이다. JDBC를 이용하다가 MyBatis를 이용하면 훨씬 편하고 코드가 간결하며 유지보수가 편하다. 마찬가지로 Hibernate도 MyBatis에 비해 코드가 훨씬 더 간결하며 객체지향적이다.

 

 

장점

 1. 생산성

 2. 유지보수

 

단점

 1. 어렵다.

 2. 성능상 문제가 있을 수 있다.

 

 

 

구글 지역별 비교 분석에서 볼 수 있듯이 한국에서는 MyBatis를 많이 사용하지만 전세계 개발자들은 Hibernate를 많이 사용한다.

 

 

 

 

사용법

 MyBatis나 기존에 자바에서 RDBMS 내의 테이블 데이터를 출력하기 위해서는 SELECT * FROM USER; 라는 query를 실행해야 했다. 하지만 JPA를 이용할 경우 user.findAll() 이라는 간단한 자바 명령어로 역할을 대신할 수 있다.

DTO 에서 객체와 DB 테이블을 매핑해주고, Repository를 만들고 나면 Controller에서 JPA에서 제공하는 몇 가지 기본적인 메소드들을 사용할 수 있다. 기본적으로는 아래 세가지를 포함한 몇가지 함수들을 제공한다.

 

- save()

- findAll()

- deleteAll()

 

 만일 커스텀 기능을 사용하고 싶을 경우 Repository에 직접 선언 후 사용할 수 있다. 예를 들어 FAQRepository에 faq 번호(no)로 검색하는 쿼리문을 동작시키고 싶을 경우 아래와 같이 함수 이름을 findByNo(int no)로 선언해주기만 하면 아래 쿼리문과 똑같이 동작하는 기능을 사용할 수 있다.

 

select * from faq where no=#{no}

 

 

 

 FAQController에서는 아래와 같이 @Autowired를 통해 FAQRepository를 연결시켜주고 repo.findByNo(no)를 통해 함수를 수행할 수 동작시킬 수 있다.

 

 

 

 

폴더 구조

- 크게 DTO, Controller, Repository, Service로 구성된다.

- Repository는 인터페이스로 findById(String no)와 같이 내가 원하는 select문의 내용에 맞게 함수의 이름을 잘 설정하면 별도의 sql문 없이도 이용할 수 있으며, 필요한 커스텀 sql문을 직접 작성해서 이용할 수도 있다.

( ex - 테이블의 primary key로 검색하고 싶을 경우 findById(String no); 라고 선언하고,

        여기에 name을 오름차순으로 select 하고 싶을 경우 findByIdOrderbyName(String no); 

        이런식으로 별도의 커스텀 쿼리문 없이 사용할 수 있다. 자세한 내용은 다음 포스팅에서 다루겠다.)

 

 

 

application.properties

spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp


spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://70.12.247.81:3306/ssafysnsdb?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=utf-8
spring.datasource.username=ssafy
spring.datasource.password=ssafy
spring.datasource.type=org.apache.commons.dbcp.BasicDataSource

# JPA
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.database=mysql

# 아래와 같이 mysql InnoDB 설정을 해줘야 foreign key가 작동한다. (default는 MyISAM)
spring.jpa.database-platform: org.hibernate.dialect.MySQL5InnoDBDialect

 

 

 

DTO Annotation 사용법

1. DTO 위

 생성자 접근 권한은 PUBLIC, PROTECTED 외 다른 것들을 지정할 수 있다. 단, PROTECTED를 설정할 경우 외부에서 해당 생성자에게 접근하는 것을 막을 수 있다. 

@AllArgsConstructor				//1. 모든 인자가 있는 생성자
@NoArgsConstructor(access=AccessLevel.PROTECTED) //2. 인자 없는 생성자
@ToString				//3. toString() 메소드 생성
@Getter					//4. @Getter, @Setter 대신 @Data로 사용할 수도 있다.
@Setter
@Entity					//5. DB테이블과 일대일로 매칭되는 객체 단위
@Table(name="notice")	//6. Notice 객체와 매핑될 테이블 이름 지정

public class Notice {	//5,6을 합쳐서 @Entity(name="notice")로 사용 가능.
						//따로 지정해주지 않을 경우 class 명과 동일하게 지어진다.
}    

 

 

2. DTO 내부 - 속성 선언


@Id						                          //테이블 primary key 지정
@GeneratedValue(strategy=GenerationType.IDENTITY) //auto_increment
@Column(length=30, nullable=false, unique=true)	  //타입 크기, not null, unique
private int no;

@Column(length=50, nullable=false)
private String title;

@Column(length=1000, nullable=false)
private String content;

@ManyToOne				   //Foreign Key 지정 - User(id)를 참조할 경우
@JoinColumn(name="id", foreignKey=@ForeignKey(name="fk_notice_user_id"))
private User user;		//User타입을 가져오는 것에 주의!!

//Date 타입 format 지정
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss", timezone="Asia/Seoul")
@Column(nullable=false)
private Date datetime;

@Column(nullable=false)
private boolean deleted;

 

 

3. 그 외 Annotation

 

 3-1. 객체 위에 사용하는 Annotation

//모든 파라미터가 있는 생성자
@AllArgsConstructor

//not null인 애들 빼고 모두 파라미터로 가지는 생성자
@RequiredArgsConstructor

 

 3-2. 속성 위에 사용하는 Annotation

//exclude - 특정 컬럼을 뺄 수 있음.
@ToString(exclude="컬럼명")

//Not null 지정. 이걸 이용할 경우 자바상에서도 에러를 잡아준다.
@NotNull

//DB타입에 맞춰서 매핑해줌.
@Temporal(TemporalType.DATE)
private Date birth;

//Boolean Type을 사용하고 싶을 경우
@Column(columnDefinition = "TINYINT", length=1)
private int deleted;

 

 

 

전체 DTO 예제

   package com.ssafysns.model.dto;
   
   import java.util.Date;				//java.util.Date를 import 해야 한다.
   
   import javax.persistence.Column;
   import javax.persistence.Entity;
   import javax.persistence.ForeignKey;
   import javax.persistence.GeneratedValue;
   import javax.persistence.GenerationType;
   import javax.persistence.Id;
   import javax.persistence.JoinColumn;
   import javax.persistence.ManyToOne;
   import javax.persistence.Table;
   
   
   import com.fasterxml.jackson.annotation.JsonFormat;
   
   import lombok.AccessLevel;
   import lombok.Data;
   import lombok.NoArgsConstructor;
   import lombok.ToString;
   
   //생성자 접근 권한 - PUBLIC, PACKAGE
   @NoArgsConstructor(access=AccessLevel.PROTECTED)
   @ToString
   @Data
   @Entity
   @Table(name="notice")
   public class Notice {
   	
   	@Id
   	@GeneratedValue(strategy=GenerationType.IDENTITY)
   	@Column(length=30, nullable=false, unique=true)
   	private int no;
   	
   	@Column(length=50, nullable=false)
   	private String title;
   	
   	@Column(length=1000, nullable=false)
   	private String content;
   	
   	@ManyToOne
   	@JoinColumn(name="id", foreignKey=@ForeignKey(name="fk_notice_user_id"))
   	private User user;
   	
   	@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss", timezone="Asia/Seoul")
   	@Column(nullable=false)
   	private Date datetime;
   	
   	@Column(nullable=false)
   	private boolean deleted;
   
   }

 

 

 

 

 

 

 

728x90

댓글