Spring/SpringDataJPA

프로젝트 생성 & 스프링 데이터 JPA와 DB설정, 동작확인

느리지만 꾸준하게 2022. 4. 15. 15:41

Appreance에서 gradle 설정 및 lombok설정

 

 

 

h2 db 실행은 여기를 참고

 - chmod + x [프로그램명]  

or

 - chmod 755 h2.sh

https://animal-park.tistory.com/301

 

[Mac] zsh: permission denied: ./h2.sh

맥 터미널에서 프로그램 실행시 "zsh: permission denied: " 에러가 발생한 경우 해결하는 방법에 대해 알아보겠습니다. 해당 오류는 말그대로 파일실행 권한이 없어서 발생한 오류인데요. 해결방법은

animal-park.tistory.com

데이터베이스 파일 생성 방법

jdbc:h2:~/datajpa (최소 한번)

  • jdbc:h2:~/datajpa
  • ~/datajpa.mv.db 파일 생성 확인

    이후 부터는 jdbc:h2:tcp://localhost/~/datajpa 이렇게 접속

 

 

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

application.properties를 삭제하고 application.yml 파일을 생성

// application.yml

spring:
  datasource:
 
  url: jdbc:h2:tcp://localhost/~/datajpa
  username: sa
  password:
  driver-class-name: org.h2.Driver
jpa:
  hibernate:
    ddl-auto: create // ddl-auto는 운영환경에서만 쓰고 개발환경에서는x
    // 애플리케이션 로딩 시점에 테이블을 다 drop을 다 한 다음에 다시 깨끗하게 생성한다.
    // 마지막에 애플리케이션 내려가도 테이블 남겨놓음 => db접근 결과확인

  properties:
    hibernate:
      # show_sql: true // JPA가 실행하는 쿼리 콘솔에 찍음
      format_sql: true
      
  logging.level:
    org.hibernate.SQL: debug // 로그파일로 남겨놓음
  #  org.hibernate.type: trace // 파라미터 바인딘됭 파라미터까지 볼 수 있는 옵션

 

entity - Member Class 

package study.datajpa.entity;


import lombok.Getter;
import lombok.Setter;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
@Getter @Setter
public class Member {


	// 식별자를 알아서 매핑
    @Id
    // JPA가 알아서 순차적인 값 넣어줌
    @GeneratedValue
    private Long id;
    private String username;


}

 

MemberRespository

package study.datajpa.repository;


import org.springframework.stereotype.Repository;
import study.datajpa.entity.Member;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Repository
public class MemberJpaRepository {

    @PersistenceContext
    // 엔티티 집어넣고 jpa가 db에다 insert query를 날려서 저장을 하게됨
    private EntityManager em;

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

    public Member find(Long id) {
        // jpa가 알아서 Member entity에 맞는 select query를 db에다가 가져오게 된다.
        return em.find(Member.class, id);
    }

}

 

test문 생성하고

 

 

Member Class를 아래와 같이 지정해준다.(@Setter 제거해도됨)

package study.datajpa.entity;


import lombok.Getter;
import lombok.Setter;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
@Getter @Setter
public class Member {

    @Id
    @GeneratedValue
    private Long id;
    private String username;


// jpa가 proxy를 쓰고 구현체가 객체를 강제로 만들어 낼 때 열어 놓아야 하므로 protected를 쓴다.
    protected Member() {
    }

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

 

MemberJpaRepositoryTest

package study.datajpa.repository;


// junit의 jupiter test
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 org.springframework.transaction.annotation.Transactional;
import study.datajpa.entity.Member;

import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
// Transactional을 걸고 밑에 비즈니스를 돌린다.
@Transactional
class MemberJpaRepositoryTest {

    @Autowired
    MemberJpaRepository memberJpaRepository;

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

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

        // 검증
        assertThat(findMember.getId()).isEqualTo(member.getId());
        assertThat(findMember.getUsername()).isEqualTo(member.getUsername());


    }
}

 

빌드 로그를 보면 테이블을 만든다.

create table member (
       id bigint not null,
        username varchar(255),
        primary key (id)
    )

 

 

 

db에서 확인을 할려면 @Rollback(false)를 넣어준다.(실무에서는 @Rollback(false)를 빼준다.)

package study.datajpa.repository;


// junit의 jupiter test
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 org.springframework.transaction.annotation.Transactional;
import study.datajpa.entity.Member;

import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
// Transactional을 걸고 밑에 비즈니스를 돌린다.
@Transactional
// 다 rollback을 시켜버리고 jpa의 영속성 컨텍스트도 flush를 안한다.
// db에 아무쿼리도 보내지 않는다.
@Rollback(false)
class MemberJpaRepositoryTest {

    @Autowired
    MemberJpaRepository memberJpaRepository;

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

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

        // 검증
        assertThat(findMember.getId()).isEqualTo(member.getId());
        assertThat(findMember.getUsername()).isEqualTo(member.getUsername());


    }
}

그러면 아래처럼 insert 쿼리문이 나오게 된다.

insert 
    into
        member
        (username, id) 
    values
        (?, ?)

 

 

isEqualTo를 넣어주면 값이 같게 나오게 된다.

package study.datajpa.repository;


// junit의 jupiter test
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 org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;
import study.datajpa.entity.Member;

import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@Transactional
@Rollback(false)
class MemberJpaRepositoryTest {

    @Autowired
    MemberJpaRepository memberJpaRepository;

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

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

        // 검증
        assertThat(findMember.getId()).isEqualTo(member.getId());
        assertThat(findMember.getUsername()).isEqualTo(member.getUsername());
        assertThat(findMember).isEqualTo(member);
    }
}

 

 

Spring data jpa를 만들자.  MemberRepository를 인터페이스로 만들고 

MemberRepositoryTest도 만들어준다.

 

아래와 같이 설정을 해주고 빌드해주면 MemberRepositoryTest를 할 때와 같은 결과가 나온다.

// MemberRepository


package study.datajpa.repository;


import org.springframework.data.jpa.repository.JpaRepository;
import study.datajpa.entity.Member;

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

package study.datajpa.repository;

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 org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;
import study.datajpa.entity.Member;

import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;


@SpringBootTest
@Transactional
@Rollback(false)
class MemberRepositoryTest {

    @Autowired
    MemberRepository memberRepository;

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

        Member findMember = memberRepository.findById(savedMember.getId()).get();

        assertThat(findMember.getId()).isEqualTo(member.getId());
        assertThat(findMember.getUsername()).isEqualTo(member.getUsername());
        assertThat(findMember).isEqualTo(member);
    }
}
drop table if exists member CASCADE 
2022-04-15 17:33:23.684 DEBUG 11328 --- [           main] org.hibernate.SQL                        : 
    
    drop sequence if exists hibernate_sequence
2022-04-15 17:33:23.686 DEBUG 11328 --- [           main] org.hibernate.SQL                        : create sequence hibernate_sequence start with 1 increment by 1
2022-04-15 17:33:23.688 DEBUG 11328 --- [           main] org.hibernate.SQL                        : 
    
    create table member (
       id bigint not null,
        username varchar(255),
        primary key (id)
    )
    
    
    insert 
    into
        member
        (username, id) 
    values
        (?, ?)

 

application.yml을 org.hibernate.type: trace를 true로 해주고

spring:
  datasource:
    url: jdbc:h2:tcp://localhost/~/datajpa
    username: sa
    password:
    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

 

build.gradle에서 dependencies에서 아래를 추가해준다.

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

그러면 빌드로그가 insert에서는 (?, ?)가 나오고  create에서는 p6spy가 나오면서 아래와 같아진다.

create table member (
       id bigint not null,
        username varchar(255),
        primary key (id)
    )
2022-04-15 17:39:05.394  INFO 11403 --- [           main] p6spy                                    : #1650011945394 | took 1ms | statement | connection 2| url jdbc:h2:tcp://localhost/~/datajpa

    create table member (
       id bigint not null,
        username varchar(255),
        primary key (id)
    )

    create table member (
       id bigint not null,
        username varchar(255),
        primary key (id)
    );
    
    
    insert 
    into
        member
        (username, id) 
    values
        (?, ?)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<출처 김영한: 실전! 스프링 데이터 JPA >

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-JPA-%EC%8B%A4%EC%A0%84/dashboard

 

실전! 스프링 데이터 JPA - 인프런 | 강의

스프링 데이터 JPA는 기존의 한계를 넘어 마치 마법처럼 리포지토리에 구현 클래스 없이 인터페이스만으로 개발을 완료할 수 있습니다. 그리고 반복 개발해온 기본 CRUD 기능도 모두 제공합니다.

www.inflearn.com