지금까지는 Oracle, MySql 등 관계형 데이터베이스를 Mybatis와 같은 SQL 매퍼를 이용해서 데이터베이스의 쿼리를 작성해왔다.
이번에는 ORM(Object Relational Mapping)
을 구현하는 자바표준 기술인 JPA(Java Persistence API)
를 이용해서 데이터를 관리하고자 한다.
ORM은 객체지향 프로그래밍 언어에서 사용되는 객체와 관계형 데이터베이스 사이의 데이터 변환 기술이다. ORM은 객체 지향적인 방식으로 데이터를 관리할 수 있도록 해주며, 객체 간의 관계를 강조하여 데이터를 저장하고 검색하는 것을 가능하게 해준다.
JPA는 ORM을 구현하는 자바 표준 기술이다. 애플리케이션 개발자가 객체를 사용하여 데이터를 저장하고 검색할 수 있도록 해주며 데이터베이스와의 통신, SQL 생성 및 실행, 객체와 테이블 간의 매핑, 캐시 및 트랜잭션 관리 등을 처리한다. 즉 객체를 사용하여 데이터베이스와 상호작용을 하도록 도와주므로 개발자는 데이터베이스와의 상호작용에 구체적인 구현을 신경쓰지 않아도 된다.
인터페이스인 JPA를 사용하기 위해서는 구현체가 필요한데 대표적으로는 Hibernate
등이 있다. 하지만 스프링에서 JPA를 사용할 때는 이 구현체들을 직접 다루지 않고, 구현체들을 좀더 쉽게 사용하고자 추상화시킨 Spring Data Jpa라는 모듈을 이용하여 JPA 기술을 다룬다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation('org.projectlombok:lombok:1.18.24')
implementation('org.springframework.boot:spring-boot-starter-data-jpa:2.7.7')
implementation('com.h2database:h2:2.1.214')
}
h2database
: 인메모리 관계형 데이트베이스인 h2database를 사용하면, 별도의 데이터베이스 서버를 설치하거나 구성할 필요 없이 애플리케이션에서 데이터베이스를 사용할 수 있다. 인메모리 데이터베이스를 사용할 경우 데이터베이스가 메모리 상에 존재하기 때문에 매우 빠르게 데이터를 처리할 수 있는 장점이 있다.
package com.myshop.web.domain.posts;
import lombok.Builder;
import lombok.NoArgsConstructor;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Column;
@Entity
@NoArgsConstructor
public class Posts {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 500, nullable = false)
private String title;
@Column(columnDefinition = "TEXT", nullable = false)
private String content;
private String author;
@Builder
public Posts(String title, String content, String author) {
this.title = title;
this.content = content;
this.author = author;
}
}
위 코드는 JPA를 사용하여 게시글을 관리하기 위한 Posts 엔티티 클래스다. 주요 어노테이션 및 코드 설명을 간단히 해보자면
@Entity
: 이 클래스가 JPA Entity임을 나타낸다. JPA Entity는 데이터베이스의 테이블
과 매핑된다.
@NoArgsConstructor
: lombok 어노테이션으로 파라미터가 없는 기본 생성자를 자동으로 생성해준다.
@Id
: 해당 필드가 엔티티의 기본키(pk)임을 나타낸다.
@GeneratedValue
: 기본키의 값을 자동으로 생성하기 위한 방법을 지정한다. GenerationType.IDENTITY
옵션을 추가해야만 auto_increment
가 된다.
@Column
: 필드가 데이터베이스의 컬럼과 매핑될 때 사용한다. length
속성은 문자열의 길이를 지정할 수 있으며(문자열의 경우 varchar(255)가 기본값이다. 사이즈를 늘리고 싶을 때 사용한다.) nullable
속성은 null값을 허용하는지 여부를 지정한다. columnDefinition
속성은 컬럼의 데이터 타입이나 기타 속성을 직접 지정할 수 있다.
@Builder
lombok 어노테이션으로 해당 클래스를 빌더 패턴을 사용하여 객체로 생성할 수 있도록 해준다. 생성자 상단에 선언 시, 생성자에 포함된 필드만 빌더에 포함된다.
여태 getter와 setter를 세트처럼 같이 사용해왔는데, Entity 클래스에는 Setter 메소드를 절대 만들지 않는다고 한다. 이유가 뭘까?
JPA에서는 객체의 상태를 변경할 때 객체의 생성자를 통해 초기화 하거나, 메소드를 추가하여 값을 변경한다. 이는 객체지향 프로그래밍의 캡슐화 원칙을 지키기 위해서다. 만약 setter 메소드를 사용하여 객체의 상태를 변경한다면, JPA는 이를 감지하지 못하게 되는 경우가 발생한다. JPA는 객체를 관리할 때 객체의 상태변화를 추적하여 적절한 SQL 쿼리를 생성하기 때문이다.
참고 : 스프링 부트와 AWS로 혼자 구현하는 웹 서비스