JPA란?
JPA는 Java Persistence API의 약자로, '자바로 영속을 처리하는 API'입니다.
JPA 상위 개념은 ORM(Object Relation Mapping)으로, 객체지향으로 구성한 시스템을 관계형 데이터베이스에 매핑하는 패러다임입니다.
JPA는 스프링과 연동할 때Spring Data JPA
라이브러리를 사용합니다.
JPA를 이용하는 개발의 핵심은 객체지향을 통해서 영속 계층을 처리하는 것입니다.
PK(기본키)를 가지는 자바의 객체입니다.
고유 식별을 위해 @Id
를 이용해 객체를 구분하고 관리합니다.
@Entity
가 존재하고 객체 식별을 위한 @Id
가 필요합니다.domain
패키지 안에 Entity들을 구성합니다.데이터베이스에 추가될 때 생성되는 번호(auto increment)를 이용할 때 사용합니다.
키 생성 전략의 GenerationType의 종류는 아래와 같습니다.
@SequenceGenerator
필요@TableGenerator
필요@MappedSuperClass
이용CreatedAt, modifiedAt과 같이 공통으로 사용되는 컬럼들을 지정하고 해당 클래스를 상속해서 이를 손쉽게 처리합니다.
엔티티들을 정의하는 클래스에서 MappedSuperClass가 적용된 클래스를 상속하여 작성합니다.
엔티티가 데이터베이스에 추가되거나 변경될 떄 자동으로 시간 값을 지정할 수 있습니다.
@EntityListeners(AuditingEntityListener.class)
를 붙여 사용합니다.@EnableJpaAuditing
을 추가해주어야 합니다.Spring Data JPA는 자동으로 객체를 생성하고 이를 통해 예외 처리를 자동으로 합니다.
이를 위해서 제공되는 인터페이스가 JpaRepository 입니다. JpaRepository를 단순히 상속하는 것만으로 인터페이스는 Entity에 대해 아래의 기능을 제공하게 됩니다.
JpaRepository interface를 상속받아서 관리하고자 하는 클래스, ID 필드 타입을 JpaRepository<Entity Class, PK type>
같이 넣어주면 자동으로 DB와 CRUD 연결을 할 수 있는 메소드를 생성합니다.
method | 기능 |
---|---|
<S extends T> S save(S) | 새로운 엔티티는 저장하고, 이미 있는 엔티티는 병합한다. |
count() | 레코드 개수를 반환한다. |
delete(T) | 엔티티 하나를 삭제한다. |
Optional<T> findById(ID) | ID로 엔티티 하나를 조회한다. |
List<T> findAll(...) | 모든 엔티티를 조회한다. 정렬(Sort)이나 페이징(Pageable) 조건을 파라미터로 제공할 수 있다. |
Spring Data JPA는 메서드의 이름으로 쿼리를 생성합니다.
우리는 JPARepository를 상속한 인터페이스 안에 규칙에 맞게 메서드를 선언하기만 하면 됩니다.
메서드 이름에 관한 규칙은 다음과 같습니다. (By 다음에는 필드명이 들어간다.)
쿼리 종류 | 이름 규칙 |
---|---|
조회 | find...By , read... By , query...By , get...By |
COUNT | count... By 반환타입 long |
EXISTS | exists...By 반환타입 boolean |
삭제 | delete...By , remove...By |
DISTINCT | findDistinct , findMemberDistinctBy |
LIMIT | findFirst3 , findFirst , findTop , findTop3 |
+엔티티의 필드 명이 변경되면 인터페이스에 정의한 메서드 이름도 같이 변경해야 합니다.
메서드명 By 뒤에 작성되는 키워드로 SQL의 Where절 내 명령어와 같은 역할입니다. 아래 키워드 표는 스프링 공식 도큐먼트에 있는 내용입니다. 더 상세한 내용은 아래 공식문서를 참조하시면 됩니다.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods
키워드 | 샘플 | JPQL |
---|---|---|
Distinct | findDistinctByLastnameAndFirstname | select distinct … where x.lastname = ?1 and x.firstname = ?2 |
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is, Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age <= ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull, Null | findByAge(Is)Null | … where x.age is null |
IsNotNull, NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection ages) | … where x.age not in ?1 |
TRUE | findByActiveTrue() | … where x.active = true |
FALSE | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstname) = UPPER(?1) |
쿼리 메서드에는 다음과 같은 파라미터들을 사용할 수 있습니다.
Pageable
, Slice
, Sort
Page<User> findByLastName(String lastname, Pageable pageable);
Slice<User> findByLastName(String lastname, Pageable pageable);
List<User> findByLastName(String lastname, Sort sort);
List<User> findByLastName(String lastname, Pageable pageable);