스프링데이터 + JPA/스프링 데이터 JPA

3. 스프링 데이터 JPA, DB 설정, 동작 확인

sdafdq 2023. 11. 18. 20:39

application.properties보다 application.yml 을 더 선호하신다고.. application.properties를 지우고 만듦.

 

spring:
  datasource:
    url: jdbc:h2:tcp://localhost/./datajpa
    username: sa
    password: 1234
    driver-class-name: org.h2.Driver

  jpa:
    hibernate:
      ddl-auto: create

    properties:
      hibernate:
#          show_sql: true
        format_sql: true

logging.level:
    org.hibernate.SQL: debug
#    org.hibernate.type: trace

스프링의 데이터 소스는

url, username, password

그리고 db 종류

 

jpa에서는

ddl-auto옵션은 개발할 때 편리하게 바꾸면서 실험해 볼 수 있다. 당연히 운영환경에서 켜놓으면 안된다.

jpa의 속성, 하이버네이트는 show_sql은 말 그대로 sql 보여주는거, 즉 로그로 남겨서 보여준다.

format_sql은 그걸 sql의 format으로 맞춰서 보여주는 거고.

저기 show_sql은 주석으로 처리해놨는데, 이유가 콘솔로 남겨서 그럼.

그래서 아래

 

logging.level.org.hibernate.sql 보면 debug레벨까지,

즉 hibernate.sql을 debug레벨까지 로그를 본다는 거임.

그러면 하이버네이트가 사실 디버그 레벨에서는 나가는 쿼리까지 다 로그로 남기고 있었음.

org.hibernate.type은 그 sql 나가는데 나가는 파라미터까지 다 볼 수 있는거.

근데 p6spy라는 더 깔끔히 보여주는 걸 쓸거라 주석.

 

쿼리 나가는 거 보고 싶으면

implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0'

 

이거 종속성 추가 해 주면 됨. 설치만 해도 알아서 읽어서 보여줌

 

먼저 JPA로 한번 간단하게 만들어 봄

 

@Entity
@Getter @Setter
public class Member {
    @Id @GeneratedValue
    private Long id;

    protected Member() {
    }

    public Member(String username) {
        this.username = username;
    }

    private String username;
}

엔티티

 

@Repository
@RequiredArgsConstructor
public class MemberJpaRepository {
    private final EntityManager em;

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

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

리포지토리

 

@SpringBootTest
@Transactional
class MemberJpaRepositoryTest {
    @Autowired MemberJpaRepository memberJpaRepository;

    @Test
    public void testMember(){
        Member member = new Member("memberA");
        memberJpaRepository.save(member);

        Member findMember = memberJpaRepository.find(member.getId());

        assertThat(member.getId()).isEqualTo(findMember.getId());
        assertThat(member.getUsername()).isEqualTo(findMember.getUsername());
        assertThat(member).isEqualTo(findMember);
    }
}

그냥 save 해 보고 찾아서 같은 지 비교.

save 할 때 알아서 id도 넣어주고(영속성 컨텍스트에서)

 

그래서 id로 엔티티매니저로 찾아봐서 얻어오고,

둘이 같은 지 비교

 

같은 트랜잭션이므로, 같은 영속성 컨텍스트에서는 ==을 보장함.

영속성 컨텍스트에 있는 레퍼런스를 주는 거라서.

 

먼저 테스트 하기 위해 간단히 SpringDataJPA 만들어 봄

public interface MemberRepository extends JpaRepository<Member, Long> {
}

끝임. 저 JpaRepository<대상엔티티, ID타입>가 SpringDataJPA인데,

이렇게 하면 알아서 구현체 만든 다음 빈으로 등록시켜 줌.

그래서, 그 구현체 사용 하려면,

 

@SpringBootTest
@Transactional
@Rollback(value = false)
class MemberRepositoryTest {
    @Autowired MemberRepository memberRepository;

    @Test
    public void testMember(){
        Member member = new Member("memberA");
        Member savedMember = memberRepository.save(member);

        Member findedMember = memberRepository.findById(member.getId()).get();

        assertThat(member.getUsername()).isEqualTo(findedMember.getUsername());
        assertThat(member.getId()).isEqualTo(findedMember.getId());
        assertThat(member).isEqualTo(findedMember);
    }
}

저렇게 그냥 주입 받아서 쓰면 됨.

 

테스트 내용은 똑같음.

참고로 테스트환경에서 @Transactional은 자동으로 롤백을 시켜줌. 그래야 테스트 여러번 진행하기 편하니까.

기본이 그거기 때문에 우리는 그냥 값 남나 보기 위해 롤백 꺼버림. 그럼 커밋함.

 

여튼, 보면 우리가 구현하지도 않은 save(), findById 등 사용할 수 있음.

이거는 앞으로 자세히 배우긴 할 테지만, 프리뷰에서도 말 했듯이,

저 JpaRepository가 상속받은 인터페이스들 중에(Crud말고도 정말 많은 기능들이 있음)

CrudRepository라는 것도 있는데,

@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {

	<S extends T> S save(S entity);

	<S extends T> Iterable<S> saveAll(Iterable<S> entities);

	Optional<T> findById(ID id);

	boolean existsById(ID id);

	Iterable<T> findAll();

	Iterable<T> findAllById(Iterable<ID> ids);

	long count();

	void deleteById(ID id);

	void delete(T entity);

	void deleteAllById(Iterable<? extends ID> ids);

	void deleteAll(Iterable<? extends T> entities);

	void deleteAll();
}

이게 실제로 저 save() 타고 들어가서 본거임.

 

여튼 잘 됨. 

SpringDataJPA가 알아서 저 JpaRepository 상속 받은 거 구현체로 잘 만들어서 빈으로 등록해주고 잘 사용됨.

 

 

'스프링데이터 + JPA > 스프링 데이터 JPA' 카테고리의 다른 글

5. 순수 JPA 리포지토리  (0) 2023.11.18
4. 예제 도메인 모델 구현  (0) 2023.11.18
2. 프로젝트 생성  (0) 2023.11.18
1. 스프링 데이터 JPA  (0) 2023.11.18
0. 프리뷰  (0) 2023.11.17