본문 바로가기

Spring Boot/JPA

Spring Boot + JPA 설정

Spring data jpa를 Spring Boot와 함께 사용하는 법에 대해 알아보겠다!


설정

jpa만 사용하는 경우에 jpa관련 설정을 'persistence.xml'을 통해 굉장히 길고 복잡하게 해야 했다.
하지만 spring boot를 사용하게 되면 이러한 설정들이 설정파일(.yml이나 properties)을 통해 자동화된다.
다음은 application.yml을 통해 설정한 예시이다.

spring:
  # DB 접속 설정
  datasource:
    url: jdbc:h2:tcp://localhost/~/jpashop
    username: sa
    password:
    driver-class-name: org.h2.Driver

  # JPA 설정
  jpa:
    hibernate:
      ddl-auto: create
    properties:
      hibernate:
        show_sql: true
        formate_sql: true

#log 설정
logging:
  level:
    org.hibernate.SQL: debug
    #org.hibernate.type: trace #log 확인을 위한 option

마지막 줄에 주석처리된 `org.hibernate.type: trace`는
JPA 관련 log에서 paramater 값을 확인하기 위한 옵션이다.

'?'에 바인딩된 값을 확인할 수 있다.

trace 설정 후 찍히는 로그

 

만약에 위처럼 찍히는 게 마음에 안 들면

spring boot data source decorator lib를 통해 조금 더 깔끔하게 '?'에 바인딩되는 값을 확인할 수 있다.

나는 gradle을 사용하므로 다음 구문을 build.gradle에 추가했다.
(maven에서 사용하는 방법은 위 링크에서 확인 가능하다)

implementation "com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.7.1"

그 후 다른 추가 설정없이 그냥 코드를 실행해보면 다음과 같이 로그가 나타나는 것을 확인할 수 있다.


Repository

import 생략...

@Repository
public class MemberRepository {

  @PersistenceContext
  private EntityManager em;

  public Long save(Member member) {
    em.persist(member);
    return member.getId();
  }

  public Member find(Long id) {
    return em.find(Member.class, id);
  }
}

Spring Data JPA에서 EntityManager를 직접 사용하고싶은 경우
@PersistenceContext annotation과 함께 EntityManager를 선언하면
Spring Boot가 Entity Manager를 주입해준다.

참고로 순수 JPA만 사용하면 직접 선언해야하는 EntityManagerFactory는
application.yml(또는 .properties)로부터 설정을 읽어와서 자동으로 생성되고,
이렇게 생성된 EntityManagerFactory로부터 EntityManager도 자동으로 생성 및 주입된다.

또한 예시로 save method와 find 메서드가 만들어져있다.

보통 Spring data jpa를 사용하면 JpaRepository를 상속받는 interface를 만든다.
그리고 해당 interface는 기본적인 CRUD 기능을 제공해주므로
위와 같은 메서드들은 딱히 필요가 없다. 하지만 이 글은 내 공부의 복습차원이므로 그냥 만들어봤다~

자 이제 위 클래스의 테스트 코드를 작성해보자~


Test code 작성하기

package jpabook.jpashop.repository;

import jpabook.jpashop.entity.Member;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import javax.transaction.Transactional;

@SpringBootTest
public class MemberRepositoryTest {

    @Autowired
    MemberRepository memberRepository;

    @Test
    @Transactional
    public void test() throws Exception {
        //given
        Member member = new Member();
        member.setUsername("memberA");

        //when
        Long saveId = memberRepository.save(member);
        Member findMember = memberRepository.find(saveId);

        //then
       Assertions.assertThat(findMember.getId()).isEqualTo(member.getId());
    }

너무나 당연하게도 EntityManager는 트랜잭션 내에서만 동작할 수 있다.

DB로 select문만 나갈 때는 트랜잭션이 없어도 된다.

이러한 트랜잭션을 직접 생성 및 시작하고
에러 여부에 따라 커밋이나 롤백을 하는 부분을 직접 코드로 작성할 수도 있지만,

@Transactional Annotation을 사용하면 Spring Boot가 대신 해준다.

이렇게 트랜잭션을 관리해주는 @Transactional이 없다면 위 코드에서는 에러가 난다.

 

또한 @Transactional이 @Test와 함께 사용될 경우 test 메서드가 끝난 뒤

자동으로 rollback된다. 이렇게 편한 @Transactional을 놔두고

굳이 직접 트랜잭션 관련 설정 코드를 작성할 필요는 없을 것이다.

 

이 Annotation은 javax와 org.springframework, 2군데에서 제공하고 있다.

이 중 유용한 설정들이 많은 org.springframework에서 제공하는 @Transactional이 권장된다.

 

참고강의: 배달의 민족 개발팀장 김영한 강사님의 JPA 강의