Spring에서 JPA 사용하기

DongHwan·2021년 7월 17일
0

Spring & Spring Boot

목록 보기
4/5
post-thumbnail

JPA란 Java Persistence API의 약자로 자바의 ORM 기술 표준이다. 즉, Java에서 ORM을 사용하기 위한 인터페이스의 모음이며, 말그대로 인터페이스이기 때문에 구현체가 필요하다.
Java에서는 Hibernate, OpenJpa 등이 JPA를 구현한 구현체이고, Spring에서는 Spring Data Jpa 모듈을 제공하여 JPA를 더욱 쉽게 사용할 수 있다.

JPA를 왜 사용할까

JPA란 Java에서 ORM을 사용하기 위한 인터페이스의 모임이라고 했다. 여기서 ORM이란 Object-Relational Mapping의 약자로, 객체와 관계형DB를 매핑한다는 뜻이다. ORM을 사용하면 데이터베이스에 대한 동작을 객체를 통해 진행할 수 있으며, 개발자가 직접 SQL Query를 작성할 필요 없이 자동으로 생성해준다. 이러한 동작 방식으로 인한 장점은 다음과 같다.

  • 생산성이 뛰어나고 유지보수가 용이하다.
    • 객체지향적인 코드로 인해 더 직관적인 코드가 만들어진다.
    • 객체지향적으로 데이터를 관리하기 때문에, 전체 프로그램 구조를 일관되게 유지할 수 있다.
    • SQL을 직접적으로 사용하지 않고 객체를 사용하여 동작하기 때문에, 재사용성이 증가하고 유지보수가 편리해진다.
    • DB 스키마가 변경될 때, 테이블 수정이나 SQL 수정 등과 같은 과정이 많이 줄어든다.
  • DBMS에 대한 종속성이 줄어든다.
    • DBMS가 변경되더라도 소스, 쿼리, 구현 방법, 자료형 타입 등을 변경할 필요가 없다.
    • 즉, 개발자는 객체에만 집중하면 되고, DBMS를 교체하는 작업에도 비교적 적은 리스크와 시간이 소요된다.

ORM 기술이 이러한 장점들을 가지고 있지만, 단점이 없는 것은 아니다. 대표적인 단점으로는 어렵다. JPA의 장점을 살려 잘 사용하기까지의 학습 비용이 높으며, 잘못 사용할 경우 SQL문을 직접 작성하는 것보다 성능이 떨어질 수도 있다. 또한, 복잡한 쿼리를 사용해야하는 것이 힘들다. 통계처리와 같은 복잡한 쿼리 자체를 ORM으로 표현하는데는 한계가 있다.

즉, ORM만 고집하는 것이 아닌 자신의 프로젝트에 맞게 Mybatis와 같은 Sql Mapper을 사용할 수도 있어야 한다.

JPA 사용 방법

Dependency

Spring Boot를 사용한다면 spring-boot-starter-data-jpa를 추가하면 된다.

<dependency> 
	<groupId>org.springframework.boot</groupId> 
	<artifactId>spring-boot-starter-data-jpa</artifactId> 
</dependency>

Spring을 사용한다면 spring-data-jpa를 추가하면 된다.

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
</dependency>

Config

Spring Boot의 경우 추가 설정은 필요 없다.

Spring은 Config 파일에 Repository Interface를 탐색할 base-package를 추가해야 한다. base-package와 그 하위 패키지에 있는 Repository Interface를 찾아서 해당 Interface를 구현한 클래스를 Spring Bean으로 등록해준다.

<!-- xml Configuration -->
<jpa:repositories base-package="my.package.repository" />
// Java Configuration
@Configuration
@EnableJpaRepositories(basePackages = "my.package.repository")
public class AppConfig {}

Entity

import lombok.*;
import javax.persistence.*;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity(name="member")
@Table(name="my_member")
public class Member {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	private String name;
	private Integer age;

	@Builder
	public Member(String name, Integer age){
		this.name = name;
		this.age = age;
	}
}

@Entity가 붙은 클래스는 JPA가 관리하는 클래스가 되며, 해당 클래스와 테이블이 매핑된다. @Entity의 속성에는 name이 있으며 JPA에서 사용할 엔티티의 이름을 지정한다. 기본값은 클래스의 이름이다.

@Table은 엔티티와 매핑할 테이블을 지정한다. 생략시 매핑할 엔티티명을 테이블의 이름으로 사용한다. 여러가지 속성 중 name 속성으로 테이블의 이름을 정할 수 있다. 기본값은 엔티티의 이름이다.

@Id 어노테이션을 사용하면 해당 필드가 기본키(PK)가 된다.
@GeneratedValue 어노테이션을 붙이면 값을 자동으로 할당할 수 있다. 다양한 옵션이 존재하지만, 추후에 정리해서 알아봐야겠다. @GeneratedValue가 붙은 필드는 값이 자동으로 할당되기 때문에 생성자에서 초기화해줄 필요가 없다.

lombok의 @NoArgsConstructor을 붙여준 이유는 JPA의 경우, Repository에서 Entity를 조회하거나 생성할 때 기본 생성자를 이용하기 때문에, 기본 생성자를 만들기 위해 붙여줬다. 또한 접근자로 Protected를 준 이유는 개발자가 기본 생성자를 이용해 도메인 개념에 해를 가하는 객체를 생성하는 것을 방지하기 위함인데, 자세한 설명은 나중에 따로 관련 글에서 정리하려 한다. 또한, Setter를 만들지 않은 것 역시 이와 마찬가지의 이유이며 추후 다시 정리하려 한다.

Repository

Spring은 Repository 인터페이스가 상속된 인터페이스를 찾아 Repository Bean 객체로 만들어준다. Repository 인터페이스를 상속받고 있는 JpaRepository<Entity, 기본키 타입>을 상속받으면, Spring이 해당 인터페이스를 바탕으로 기본적인 CRUD를 가지는 Bean 객체를 자동으로 생성한다.
JpaRepository 상속 구조 JPA 처리를 담당하는 Repository는 JpaRepository말고도 기본적으로 3가지가 더 있으며, 상속관계를 통해 기능들을 제공한다. 필요한 기능에 맞게 적절한 인터페이스를 선택하면 된다.

public interface MemberRepository extends JpaRepository<Member, Long> {
	// 비어있어도 잘 작동하며, Generic의 Id는 primitive가 아닌 wrapper 클래스를 넣어주자

	// findBy 뒤에 컬럼명을 붙여 이를 이용한 검색이 가능하다.
	Optional<Member> findByName(String name);

	// findAllBy 역시 가능하다.
	List<Member> findAllByName(String name);

	// like 검색도 가능하다.
	Optional<Member> findByNameLike(String name);
}

etc

Entity와 Repository를 만들어주었으면, 나머지 계층에서 사용하면 된다.

추가적으로 Entity(Domain) 계층과 VO 혹은 DTO 계층을 나누어서 사용해야 한다. Entity 객체로 request나 response를 처리하면 안된다!! 이는 View Layer와 DB Layer의 역할을 철저하게 분리하기 위함으로, 테이블과 매핑되는 Entity가 변경되면 여러 클래스에 영향을 끼치지만 View와 통신하는 DTO 클래스는 자주 변경되기 때문에 분리를 해야한다. 그 이외에도 여러가지 이유가 있지만, 핵심적인 이유는 View Layer와 DB Layer의 역할을 분리하기 위함으로 알면 된다.

참조 링크

[jpa] Spring Data JPA

profile
날 어떻게 한줄로 소개해~

0개의 댓글