spring

[JPA] table, entity 만들고 테스트하기

고줭 2022. 2. 19. 16:30

안녕하세요 정말 너무너무너무너무너무너무 간만에 글 씁니다.
근황이라면 회사에서 새롭게 템플릿 리뉴얼하느라 평일, 주말, 밤낮없이 일하면서 지내고있습니다.

어느덧 코로나 확진자 수가 10만까지 도달했는데 다들 잘 계시나요? 운동도 요즘은 일 때문에 못가고 일 -> 집 -> 일 ... 이 무한반복인 저는  건강하게 잘 지내고 있습니다. 
원래 집돌이인 성격에 나가지도 않아서 걸릴 틈이 없네요. 건강하길 바라며 지금 하는 것을 잠깐 소개할까 합니다.

원래 만들어놨던 웹 서비스가 mybatis를 사용해서 DB로부터 데이터를 주고 받았는데요. 회사에서 새 프로젝트를 JPA로 하다보니 문득 JPA를 적용해지고 싶어졌습니다. 출퇴근길 영상으로만 강의 보다가 오늘에서야 드디어 첫 발을 뗏습니다.

테이블 만들기
create table merchant(
    merchant_id   bigint primary key,
    merchant_code VARCHAR(50),
    merchant_name VARCHAR(50),
    reg_date      DATETIME DEFAULT CURRENT_TIMESTAMP,
    mod_date      DATETIME ON UPDATE CURRENT_TIMESTAMP,
    use_yn         char(1)  DEFAULT 'Y'
);

create table theme(
    theme_id   bigint primary key,
    company_name varchar(255),
    merchant_id bigint NOT NULL ,
    theme_code VARCHAR(50),
    theme_name VARCHAR(50),
    reg_date      DATETIME DEFAULT CURRENT_TIMESTAMP,
    mod_date      DATETIME ON UPDATE CURRENT_TIMESTAMP,
    use_yn         char(1)  DEFAULT 'Y',
    FOREIGN KEY (merchant_id) REFERENCES merchant(merchant_id)
);

첫 번째로 고민한건 DB의 설계였습니다. 우선 JPA가 제대로 적용되는지를 확인하기 위해 컬럼과 데이터 수가 적은 theme, merchant만 만들었습니다.

각각의 id값은 테이블 이름을 붙였고 데이터는 많지 않지만 bigint로 설정했습니다. reg_date는 기본적으로 만들 때의 시간이 들어가게끔 default current_timestamp를 넣었고 mod_date는 update시에 current_timestamp가 들어가게끔 설계했습니다.

theme table에는 merchant_id를 foreign key로 지정했습니다.

merchant table
theme table

theme table에 company_name컬럼을 merchant_id와 바꿔야 할 것 같은 느낌이 들지만 우선 테스트를 위해서 그대로 두겠습니다.

Java Code
package com.example.jpa.repository;

import com.example.jpa.entity.Merchant;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface HintRepository extends JpaRepository<Merchant, Long> {
}

Repository interface를 만들고 JpaRepository를 extends해줍니다. 기본적으로 findAll(), findById()등을 지원하기 때문에 필요에 의한 메서드가 없다면 그대로 사용해도 됩니다. 제네릭의 첫번째 인자는 ORM형태로 검색할 Entity class 이고 뒤에 나오는 Long은 key의 자료형입니다.

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.2">
    <persistence-unit name="xcape">
        <properties>
            <!-- 필수속성 -->
<!--            <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>-->
<!--            <property name="javax.persistence.jdbc.user" value="사용자"/>-->
<!--            <property name="javax.persistence.jdbc.password" value="비밀번호"/>-->
<!--            <property name="javax.persistence.jdbc.url" value="DbUrl정보"/>-->
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
        </properties>
    </persistence-unit>
</persistence>

resources/META-INF/persistence.xml 입니다.
강의에서는 주석처리해놓은 요소들도 넣어서 하던데 SpringDataJPA와 hibernate의 차이인지 Spring에서는 application.properties에 적용하는게 우선이라 그런지 주석처리한 부분은 application.properties에 써야 하더라구요.

#DB 정보
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=DB Url
spring.datasource.username=사용자
spring.datasource.password=비밀번호

#JPA
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect

application.properties에 적용한 내용입니다. 당연히 DB정보에 대한건 필수이고 아래 JPA영역은 옵션이니까 굳이 안해도 됩니다. 각 옵션에 대해서는 적진 않겠습니다.

package com.example.jpa.entity;

import com.example.jpa.repository.HintRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
public class JpaTest {

    @Autowired
    private HintRepository hintRepository;

    @Test
    public void 엔티티_테스트() {
        List<Merchant> merchantList = hintRepository.findAll();

        for (Merchant merchant : merchantList) {
            System.out.println(merchant.getMerchantCode());
            System.out.println(merchant.getMerchantName());
            System.out.println("-------------------");
        }
    }

}

모든 Merchant가 받아지기위해 Test Class를 만들었습니다. 어떤 이유인지 @SpringBootTest 대신 @DataJpaTest가 안되고 생성자 주입방식을 사용하면 안되더라구요. 우선 Jpa가 잘 작동하는지가 우선이니까 이유는 뒤로하고 되는대로 코드를 작성했습니다.

테스트결과가 잘 받아집니다. JPA 기본적 사용법은 알았으니 다음은 가장 중요한 Hint table설계에 대해 고민해봐야 할 것 같습니다. table설계가 무사히 끝나는대로 글 올리겠습니다.