인프런 커뮤니티 질문&답변

devholic님의 프로필 이미지
devholic

작성한 질문수

스프링 DB 2편 - 데이터 접근 활용 기술

테스트 - 임베디드 모드 DB

임베디드 모드 테스트 시 sql 스크립트

해결된 질문

작성

·

736

·

수정됨

0

[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예/아니오) 예
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예

[질문 내용]
여기에 질문 내용을 남겨주세요.

영한 님의 강의를 수강한 뒤 간단한 게시판 프로젝트를 작업해보고 있습니다.

말씀해주신 임베디드 모드를 테스트에 적용하기 위해 다음과 같이 설정해봤습니다.

test의 resources/application.properties에는 단순히 로그와 관련된 것만 입력해두었습니다.

logging.level.org.springframework.jdbc=debug

# Can check SQL which Hibernate run and create
logging.level.org.hibernate.SQL=DEBUG

# Can check parameters which binding in SQL
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

멤버 엔티티입니다.

package com.devholic22.board.entity;

import jakarta.persistence.*;
import lombok.Data;

@Data
@Entity
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "user_name", length = 10)
    private String name;

    @Column(length = 10)
    private String password;

    public Member() {
    }

    public Member(String name, String password) {
        this.name = name;
        this.password = password;
    }
}

멤버 리포지토리입니다.

package com.devholic22.board.repository;

import com.devholic22.board.entity.Member;
import org.springframework.data.jpa.repository.JpaRepository;

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

테스트 코드입니다.

package com.devholic22.board.repository;

import com.devholic22.board.entity.Member;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@Slf4j
@SpringBootTest
public class MemberRepositoryTest {

    @Autowired
    MemberRepository repository;

    @Test
    void save() {
        Member member = new Member("testerA", "1234");
        Member savedMember = repository.save(member);
        log.info(savedMember.toString());
    }
}

그런데 강의에서 이야기하셨던 SQL 스크립트를 만들어두지 않았는데도, 테스트가 제대로 실행되었습니다.

원래 예상했던 결과는 Table "MEMBER" not found와 같은 부분인데, 왜 이런 에러가 발생하지 않았는지 궁금합니다.

테스트 코드 결과입니다.

2022-12-11T13:15:08.008+09:00  INFO 65418 --- [           main] c.d.b.repository.MemberRepositoryTest    : Started MemberRepositoryTest in 7.134 seconds (process running for 9.374)
2022-12-11T13:15:08.427+09:00 DEBUG 65418 --- [           main] org.hibernate.SQL                        : insert into member (id, user_name, password) values (default, ?, ?)
2022-12-11T13:15:08.501+09:00  INFO 65418 --- [           main] c.d.b.repository.MemberRepositoryTest    : Member(id=1, name=testerA, password=1234)
2022-12-11T13:15:08.547+09:00  INFO 65418 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2022-12-11T13:15:08.549+09:00  INFO 65418 --- [ionShutdownHook] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down'
2022-12-11T13:15:08.550+09:00 DEBUG 65418 --- [ionShutdownHook] org.hibernate.SQL                        : drop table if exists member cascade 
2022-12-11T13:15:08.555+09:00  INFO 65418 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2022-12-11T13:15:08.560+09:00  INFO 65418 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

 

답변 1

1

안녕하세요. Hyunjoon Choi님, 공식 서포터즈 OMG입니다.
.

h2 인메모리를 사용했을 때, ddl-auto의 기본값이 create-drop이여서 말씀하신 상황이 발생한 것 같습니다.

imagehttps://pravusid.kr/java/2018/10/10/spring-database-initialization.html

 

로그에서도 확인할 수 있는데요, 테스트 종료 시 table을 드랍하고 있네요.

drop table if exists member cascade 

해당 로그 이전 스프링 컨테이너가 실행되는 띄울 때 create 문이 확인될까요?
.
감사합니다.

devholic님의 프로필 이미지
devholic
질문자

확인하였습니다.

그렇다면

@Bean
@Profile("test")
public DataSource dataSource() {
    ...
}

와 같은 메모리 DB용 데이터소스를 직접 만들었을 경우에만 schema.sql 같은 SQL문을 별도로 만들어야 하고, 완전히 임베디드 모드를 스프링이 실행시키도록 할 때는 (질문과 같이 데이터베이스에 대한 정보들이 모두 없도록 할 때) ddl-auto의 값을 별도로 변경하지 않는 이상은 schema.sql을 작성하지 않아도 되는 것인가요? 이 경우는 @Entity@Column을 토대로 데이터베이스 테이블을 자동으로 만들어주는 것으로 이해하면 되는 것인지 궁금합니다.

 

추가) 영한 님의 자료를 더 찾아보니 예외와 트랜잭션 커밋, 롤백 - 활용 부분에서도 관련 내용이 언급되어 있네요.

image

확실히 spring.jpa.hibernate.ddl-auto=none으로 하니 강의처럼 테이블이 없는 오류가 나왔습니다.

그런데 제가 궁금한 것은 이 경우도 그렇고 지금 이 강의에서의 경우도 똑같이 메모리 DB를 사용하는 방식인데, 왜 이 강의에서는 sql 스크립트를 별도로 만들어야 한다고 하고 지금 경우에서는 sql 스크립트가 필요하지 않은지 차이를 잘 모르겠습니다.

 

SQL 스크립트의 예 (sql/schema.sql)

drop table if exists member;
create table member (
    id bigint generated by default as identity,
    member_name varchar(10),
    password varchar(10),
    primary key (id)
); 

 

영한 님의 설명

image

++ 강의를 계속 반복적으로 복습해 본 결과, JdbcTemplate을 사용했을 때는 src/test/resources/schema.sql 파일을 필요로 함을 알았습니다. 이에 반해, 위의 경우처럼 JPA를 사용했을 때는 sql 파일이 없어도 됨을 알았습니다. 또한, 이 이유는 Hibernate에도 기본 실행 스크립트가 있기 때문인 것도 알았습니다.

그렇다면 차이점의 원인은 @Entity에 있는 것인가요? 개인적으로 드는 생각은 @Entity를 통해 임베디드 데이터베이스에 테이블을 등록하게끔 Hibernate의 기본 스크립트에 작성되기 때문에 문제가 없는 것인가.. 생각이 드는데 이게 맞는 원리인지 검증되지 않아 질문드립니다. 

답변 드리기에 앞서 영한님의 JPA강의나 별도의 JPA 학습없이 여기까지(댓글) 추론하신 것이면 대단하네요 ^^

그렇다면 차이점의 원인은 @Entity에 있는 것인가요? 개인적으로 드는 생각은 @Entity를 통해 임베디드 데이터베이스에 테이블을 등록하게끔 Hibernate의 기본 스크립트에 작성되기 때문에 문제가 없는 것인가.

 

 

네 맞습니다.

JPA 설정

강의를 보셨다면 아시겠지만, build.gradle에 spring-data-jpa의존성을 추가한 것을 보셨을텐데요, 해당 의존성이 우리의 프로젝트에서 jpa를 사용하겠다는 준비와 같다면

@Entity는 JPA가 관리할 객체로 등록합니다.

그리고 애플리케이션이 실행될 때 DB의 테이블과 매핑이 되며, 이게 ORM(객체와 관계형 데이터베이스의 매핑)기술입니다. 댓글에 ++로 추가로 남긴 내용이 결국 JPA의 동작을 설명하신 것이며,

@Entity는 JPA에서만 사용하는 점을 참고해주세요(JdbcTemplate, jdbc, mybatis X)

 

 

devholic님의 프로필 이미지
devholic
질문자

답변 감사합니다!!

devholic님의 프로필 이미지
devholic

작성한 질문수

질문하기