JDBC -> JdbcTemplate 로 바꾸면 반복적인 코드가 줄게 되지만, SQL은 여전히 개발자가 직접 작성해야 한다.
✨ 하지만 JPA를 사용하면 SQL 쿼리도 JPA가 처리를 해줘 개발 생산성을 높일 수 있다.
< build.gradle >
// implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
이제 jdbc 라이브러리는 지우고, jpa 라이브러리를 추가한다!
jpa 라이브러리 내부에 jdbc 관련 라이브러리를 포함하기 때문에 지워도 된다.
< application.properties >
spring.jpa.show-sql=true // JPA가 날리는 SQL을 볼 수 있다.
spring.jpa.hibernate.ddl-auto=none
Member 객체에 가서 @Entity 와 @Id, @GeneratedValue 어노테이션을 달아준다.
< Member >
@Entity
public class Member {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
여기서 아래 문장을 살펴보면, pk를 설정하고 전략은 IDENTITY이다.
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
데이터베이스에 이름만 넣으면 id는 데이터베이스에서 알아서 자동으로 생성된다. 이것을 IDENTITY라고 한다.
JPA는 스프링부트가 우리가 셋팅한 정보와 데이터베이스 커넥션 정보 등을 연결하여 만들어주는 EntityManager에 의해 모든 것이 동작한다.
pk 기반이 아닌 나머지 것들 (findByName, findAll) 은 jpql 작성하였다. 이것은 추후 스프링 데이터 JPA로 사용하면 jpql을 쓰지 않아도 된다.
🚩 @Transactional : 테스트 케이스가 아닌, 서비스 계층에 트랜잭션을 추가한다. JPA는 모든 데이터 변경이 @Transactional 안에서 실행되어야 한다. 스프링은 해당 클래스의 메서드를 실행할 때 트랜잭션을 시작하고, 메서드가 정상 종료되면 트랜잭션을 커밋한다. 만약 런타임 예외가 발생하면 롤백한다.
JPA 기술을 스프링에서 한 번 감싸서 제공하는 것
< SpringDataJpaMemberRepository >
public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository {
@Override
Optional<Member> findByName(String name);
}
JpaRepository와 MemberRepository를 extends로 상속 받는다.
인터페이스와 인터페이스 간의 상속은 extends 이다!
여기서 findByName의 JPQL는 아래를 의미한다.
select m from Member m where m.name = ?
실무에서는 JPA와 스프링 데이터 JPA를 기본으로 사용하고, 복잡한 동적 쿼리는 Querydsl이라는 라이브러리를 사용하면 된다. Querydsl을 사용하면 쿼리도 자바 코드로 안전하게 작성할 수 있고, 동적쿼리도 편리하게 작성할 수 있다. 이 조합으로 해결하기 어려운 쿼리는 JPA가 제공하는 네이티브 쿼리를 사용하거나, 앞서 학습한 스프링 JdbcTemplate를 사용하면 된다.
JPA, 스프링 데이터 JPA, Querydsl 기술을 조합해서 쓰기도 한다.