Spring Data JPAimplementation 'org.springframework.boot:spring-boot-starter-data-jpa'。
JAVA의ORM 기술인JPA를 더 간단하게 사용할 수 있도록 사용하는Spring JPA 라이브러리
▶JPA의EntityManager를 직접 사용하는 대신 간단하게JpaRepository<Entity Type,Key Type>를 확장하여 활용
。Spring Data JPA내부에Hibernate를 포함한다.
。Spring Data JPA의 각 작업은트랜잭션을 사용하지 않는 경우DAO 작업자체를 차단.
▶@Transactional을 선언하여트랜잭션을 제어.
。JPA의Hibernate를 사용하기 전에는 무조건 사용할데이터베이스를 사전에 정의해야한다.
。ORM 환경에서는PK의매직넘버로 찾으면 안된다.
▶ 찾은Entity 객체가 포함하는PK를 활용해서 찾아야함.
。Spring JPA는동적쿼리를 작성하지 못하는 단점이 존재
▶QueryDSL을 통해 개선
따로
Repository Class를 정의할 필요없이CRUD를 수행할DB Entity를JpaRepository<Entity Type,Key Type>로 설정하여확장하는Repository 인터페이스를 선언 및Service Class에필드로 선언하여CRUD수행public interface MemberRepository extends JpaRepository<MemberEntity, UUID> { }@RequiredArgsConstructor @Service public class MemberService { // 생성자 의존성 주입 private final MemberRepository memberRepository }▶
Service Class의필드에 해당인터페이스 구현체를 선언 시Spring Context에서 자동으로JpaRepository 구현체를의존성주입하여JpaRepository API(save()등 )를 호출 시Course Entity에 대한CRUD를Entity Manager에 의해 수행
Spring Data JPA원리
。Spring Data JPA는 기본적으로EntityManger를 활용한CRUD 메서드를일반화를 통해 기본 구현하여 제공
▶개발자가CRUD 메서드를 구현할 필요 없이Generics에타입 지정후 해당메서드를 사용
Spring Data JPA는 기본적으로 어떤Entity 도메인에 대해서 공통적으로일반화된CRUD 메서드를기본 구현하여 제공
。JpaRepositry<Entity클래스,ID타입>을 지정 시 상위인터페이스인SimpleJpaRepository -> CrudRepository ...순으로Entity 클래스에 대해Generics가 설정
▶Spring JPA내 기본 구현된CRUD 메서드들은Generics에 지정된Entity Class를 기반으로작업을 수행@Override @Transactional public <S extends T> S save(S entity) { Assert.notNull(entity, ENTITY_MUST_NOT_BE_NULL); if (entityInformation.isNew(entity)) { entityManager.persist(entity); return entity; } else { return entityManager.merge(entity); } }▶
SimpleJpaRepository내 구현된save() 메서드로서JpaRepository<Entity클래스,ID타입>를 지정 시 해당Entity클래스로Generic이 지정.
JpaRepository<Entity클래스,ID타입>을확장한Repository 인터페이스를의존성 주입시Entity 클래스로Generics가 지정된SimpleJpaRepository 구현체가 주입
。따로Repository 인터페이스 구현체를 설계하지 않아도, 자동으로 해당Entity 클래스로Generics가 지정된SimpleJpaRepository 구현체가Repository 인터페이스의Spring Bean으로 등록
▶ 해당Spring Bean을의존성 주입받은 후Spring Data JPA에서 기본 구현된Crud 메서드를 사용
Spring Data JPA관련환경설정spring: jpa: hibernate: ddl-auto: update properties: hibernate: format_sql: true dialect: org.hibernate.dialect.MySQLDialect jdbc: time_zone: Asia/Seoul show_sql: true。
application.yml의spring: jpa에서 설정하는 내용
。Spring Boot의application.yml에서spring.datasource의 설정을 수행하는 경우, 해당 설정값을 기반으로DataSource 객체가 생성되어Spring Bean으로 등록
▶DataSource 구현체의 경우Hikari Connection Pool을 기반으로 생성됨.datasource: url: jdbc:h2:mem:test-db;MODE=MYSQL; username: sa password: driver-class-name: org.h2.Driver
▶application.yml의DataSource 설정을 기반으로HikariCP가 생성되어Spring Bean으로 등록
spring: jpa: hibernate: ddl-auto
。Spring Boot기동 시점에서JPA에 의한DB Schema에 대한 처리방법을 결정하는 옵션
▶ddl-auto설정 시hibernate에 의해DB Entity를 기준으로DB에매핑된Table이 생성
。실무에서는보수적으로ddl-auto를 설정
▶운영서버에서는ddl-auto: none / validate를 사용
▶개발서버는ddl-auto: none / validate / update,로컬서버는 상관없이 사용
。ddl-auto: create: 기존DB Table을 전부DROP후DB Entity기반으로 새롭게 생성
▶개발 / 테스트 환경에서초기화시 유용
。ddl-auto: create-drop:create와 동일하나어플리케이션 종료 시점에서 모든DB Table을Drop
▶ 모든 데이터가 삭제되는 위험성이 존재하므로테스트 환경에서만 사용
。ddl-auto: update:DB Table Scheme와DB Entity 구조간 차이가 존재하는지 검사 후DB Table에업데이트
▶ 단Entity가 삭제되더라도DB Table또는Column의Drop은 수행하지 않는다.
▶ 주로개발 / 로컬환경에서 사용
。ddl-auto: validate:DB Table Scheme과Entity 클래스 구조간 서로 일치하는지 검사만 수행
▶ 불일치하는 경우예외를 발생하여어플리케이션이 구동되지 않도록 설정
。ddl-auto: none:hibernate를 적용하지 않도록 설정하여, 아무런 작업도 수행하지 않는다.
▶ 주로운영환경에서validate와 함께 사용
spring: jpa: properties: hibernate: format_sql: true
。Hibernate가 생성 및 실행하는SQL Query를콘솔에 출력 시 가독성이 좋도록들여쓰기 / 줄바꿈하여 포맷팅.
spring: jpa: properties: hibernate: dialect: org.hibernate.dialect.MySQLDialect
。JPA또는Hibernate에서 사용하는특정 DB에 해당하는SQL문법과기능을 사용하도록 설정
。 각DB는 통일된ANSI SQL를 사용하나 각각 작은 차이가 존재하므로 보완할 필요가 존재
▶Hibernate는 해당 문법/기능적 차이를Dialect를 통해 자동으로 조정
spring: jpa: properties: hibernate: jdbc: time_zone
。DB Entity의저장시 시간을 통일하기위해 지역을 설정
time_zone: Asia/Seoul
spring: jpa: show_sql: true
。jpa가 생성 및 실행하는SQL Query를콘솔에 출력
JpaRepository<Entity class, PK field Type>:
。Spring Data JPA에서 제공하는 설정된Entity에 대한CRUD기능을 제공하는인터페이스
▶영속성 컨텍스트에 등록된DB Entity에 대해Entity Manager에 의해 자동으로Query를 수행하는API(save()등 )를 제공.
。Repository 인터페이스 구현체는Entity 클래스가Generics로 지정된JpaRepository<> 인터페이스의SimpleJpaRepository 구현체가Spring Bean으로 등록되어의존성 주입
▶Entity 클래스가Generics로 지정된 해당SimpleJpaRepository에 기본 구현된CRUD API를 사용가능
。 기존Spring JDBC의JdbcTemplate 객체의 경우 직접SQL을 작성하여CRUD하는 방식에 비해 매우 간편하게 사용가능
Spring Data CRUD API메서드
。Spring Data JPA는 기본적으로EntityManger를 활용한CRUD 메서드를일반화를 통해 기본 구현하여 제공
▶개발자가CRUD 메서드를 구현할 필요 없이JpaRepository<>의Generics에Entity Class의타입 지정후SimpleJpaRepository를의존성 주입받아 해당메서드를 사용
。Paging 기능을 기본으로 제공
。각API는 용도에 맞는SQL들이 내장되어 호출만해도 동적으로 요소가 자동으로 변경되어 적용
구현체.flush():
。commit시 호출되어영속성 컨텍스트내 기존Pending 상태인 모든Entity를매핑된DB Table에 일괄적으로 반영하도록DB에SQL을 전송하는 역할을 수행
▶Pending:DB Entity변경내용이DB에 반영되지않고영속성 컨텍스트에만 반영된 상태
구현체.saveAndFlush(DBEntity객체)
。Pending 상태의 특정Entity만 선택하여매핑된DB Table에 반영하는Update SQL을 전송
▶EntityManager.persist()를 수행 후flush()를 수행하는로직을 포함@Override @Transactional public <S extends T> S saveAndFlush(S entity) { S result = save(entity); flush(); return result; }
구현체.save(DBEntity객체):
。영속성 컨텍스트에EntityManager객체.persist()에 의해DB Entity 객체를INSERT하는 역할을 수행하는API
▶ 이후flush()를 통해DB Table에 반영
。동일한식별자를 가진DB Entity를save()하는 경우UPDATE로 수행
▶ 기존DB Entity는UPDATE, 새로운DB Entity는INSERT
구현체.delete(DBEntity객체)
。영속성 컨텍스트의 해당DB Entity를Soft Delete수행
▶영속성 컨텍스트내에서 해당DB Entity가삭제 예정으로 등록
구현체.deleteById(Id)
。영속성 컨텍스트의 해당DB Entity를Hard Delete수행
구현체.findById(Id)
。SELECT역할 수행
。JpaRepository의findById()사용 시NPE를 방지하기위해영속성 컨텍스트에서 조회한Entity를Optional<Entity타입>으로 반환Optional<User> user = userRepository.findById(id); User user1 = userRepository.findById(id).get();。
JpaRepository는 DB의Id로 검색하는findById()는 기본적으로 제공하지만, Field명으로 검색하는 기능은 구현이 되지 않았으므로, 해당 기능의Custom Method를 구현
구현체.count():
。특정DB Table의DB Entity의 갯수 확인
구현체.findAll():
。@Entity를 통해 특정DB Entity Class와Mapping된DB Table의 모든DB Entity를List<Entity객체>으로 return@GetMapping(path="/jpa/users") public List<User> ListAllUsers(){ List<User> users = userRepository.findAll(); return users; }
구현체.getReferenceById():
。DB Table에서ID에 해당하는Spring Bean을 return.