본문 바로가기
spring

spring mybatis로 RDB select 해보기

by 토망이 2023. 6. 25.

본 글에서는 RDBMS를 사용할때 종종 사용하는 mybatis를 활용하여 SQL 쿼리를 사용, CRUD 중에서 기본적인 Select 쿼리를 호출하는 api를 만들어보도록 하겠습니다.

 

실무에서는 Oracle DB를 주로 사용하였으나, test를 위해서 무료로 쉽게 사용가능한 RDBMS인 H2 Database를 사용하였습니다. H2 설치와 관련해서는 이전글을 참고해주세요.

H2 Database 설치 가이드 

 

H2 Database 설치 가이드

본 글에서는 H2 Database를 설치하는 내용을 다루려합니다. 실무에서는 주로 RDBMS를 oracle을 사용하고 있지만, 집에서 공부할때 Mongodb와 같은 nosql 말고 RDBMS가 필요하여, 무료로 쉽게 테스트 할 수 있

dnl1029.tistory.com

 

먼저, DB와 mybatis 사용을위해 H2 DB에 테이블을 생성 후, 아래와 같이 MEMBER라는 테이블에 샘플 데이터를 입력했습니다.

CREATE TABLE MEMBER(USER_ID VARCHAR(255) PRIMARY KEY, 
NAME VARCHAR(255),
PASSWORD VARCHAR(255));

INSERT INTO MEMBER(USER_ID, NAME, PASSWORD) VALUES('aa','test1','aa123');
INSERT INTO MEMBER(USER_ID, NAME, PASSWORD) VALUES('bb','test2','bb123');
INSERT INTO MEMBER(USER_ID, NAME, PASSWORD) VALUES('cc','test3','cc123');
INSERT INTO MEMBER(USER_ID, NAME, PASSWORD) VALUES('admin','administrator','admin123');

 

- pom.xml

의존성은 mybatis와 h2 둘다 추가해줍니다.

<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>3.0.1</version>
</dependency>

<dependency>
	<groupId>com.h2database</groupId>
	<artifactId>h2</artifactId>
	<scope>runtime</scope>
</dependency>

 

- application.yml

: mybatis 설정값에 대한 설명은 주석으로 추가했습니다. spring 관련 설정중에 lifecycle, mongodb에 대한 설정은 무시하고 datasource 내의 설정만 참고하시면 됩니다. h2 콘솔에서 연결 url을 아래와 같이 수정하였습니다. 이유는 뒤에 다루겠습니다.

------------------------------------

기존
jdbc:h2:~/test

변경
jdbc:h2:tcp://localhost/~/test

------------------------------------

#Mybatis Configuration
mybatis:
  mapper-locations: META-INF/mybatis/mappers/*.xml #query가 들어가있는 xml파일 위치 지정
  configuration:
    map-underscore-to-camel-case : true #DB에서 USER_ID -> userId로 DB 컬럼명과 Java 변수명 자동변환
    jdbc-type-for-null: 'NULL' #mybatis로 넘어온 값이 null인 경우에 jdbctype값. 쿼리조건에 null 넣고 싶을때 사용
    call-setters-on-nulls: true #쿼리 수행 후 가져온 값이 null인 경우, 응답으로 null을 세팅해줄지 말지 여부

spring:
  lifecycle:
    timeout-per-shutdown-phase: 40s #디폴트값은 30초
  data:
    mongodb:
#      uri: mongodb+srv://admin:내암호@cluster0.1p17esk.mongodb.net/sample_airbnb
      uri: ENC(1kiaGE3RJMoGZi9TFdjEj4IxeCJyofdL9i5bpvbN+N5pidF/5WUuNeDhGCLTXgQHUpFxFC2P1uOaEDDWv5OdLwiNVw2FT3mFNr4pB73Nb5E=)
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:tcp://localhost/~/test
    username: sa
    password:

 

- Dto

: DB와 매핑할 Dto 클래스를 작성했으며, 편의성을 위해 input 파라미터와 output을 담을 객체도 동일하게 MemberDto를 사용하였으나, 더 정확하게 사용하려면 분리해야합니다. 

@Data
public class MemberDto {

    private String userId;
    private String name;
    private String password;

}

 

- MemberMapper.xml

: mapper 파일은 application.yml에서 명시한 경로인 resources/META-INF/mybatis/mappers 경로에 .xml 파일로 만들었습니다. Input ParameterType으로 LinkedHashMap을 사용하였으며, 일반 HashMap을 사용하여도 무방합니다. ResultType으로 MemberDto를 지정해주었으며, Param 값은 name만 빼고 id와 password만 사용하였습니다.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.blog.mapper.MemberMapper">

    <select id="findMemberByMap" parameterType="java.util.LinkedHashMap" resultType="com.example.blog.dto.MemberDto">
        SELECT USER_ID,
        NAME,
        PASSWORD,
        FROM MEMBER
        WHERE 1=1
        AND USER_ID = #{USER_ID}
        AND PASSWORD = #{PASSWORD}
    </select>

</mapper>

 

- MemberMapper

: Mapper는 아래와 같이 @Mapper 어노테이션만 추가하고, interface로 선언만 하면 끝입니다. findMemberByMap이라는 메서드명과, .xml파일내의 select id="findMemberByMap"을 매핑하여, 쿼리 수행으로 인한 결과값이 매핑됩니다.

@Mapper
public interface MemberMapper {

    MemberDto findMemberByMap(LinkedHashMap<String,Object> paramMap);

}

 

- service

: MemberMapper 의존성을 주입하고, LinkedHashMap으로 paramMap을 만들어, put메서드를 통해 Controller로부터 전달받은 memberDto 파라미터값을 map에 넣습니다. 

@Service
@Slf4j
@RequiredArgsConstructor
public class MemberService {

    private final MemberMapper memberMapper;

    public MemberDto getMemberByDto(MemberDto memberDto){
        LinkedHashMap<String,Object> paramMap = new LinkedHashMap<>();

        log.info("id : {}",memberDto.getUserId());
        log.info("password : {}",memberDto.getPassword());

        paramMap.put("USER_ID",memberDto.getUserId());
        paramMap.put("PASSWORD",memberDto.getPassword());
        MemberDto result = memberMapper.findMemberByMap(paramMap);
        return result;
    }

}

 

- Controller

@RequestMapping("api/v1")
@RestController
@RequiredArgsConstructor
@Slf4j
public class MemberController {

    private final MemberService memberService;

    @GetMapping("mybatis/test")
    public MemberDto getMemberByIdPassword(@ModelAttribute MemberDto memberDto) {
        MemberDto result = memberService.getMemberByDto(memberDto);
        log.info("member : {}",result);
        return result;
    }
}

 

- swagger

: 테스트는 아래와 같이 입력해보겠습니다. name이 파라미터로 들어가진 않으니, 기본값으로 냅둬도 크게 문제없습니다.

 

- 결과 

: 아래와 같이 Database may be already in use ... 라는 에러가 뜹니다.

해결방법으로, 해당 로그에서 확인되는 경로로 가서(C://개인경로/test.mv.db) test.mv.db 파일을 삭제합니다. 그 후 H2 콘솔에서 접속 url을 아래와 같이 수정하고, application.yml에서도 동일하게 수정합니다. 그 후 서버를 재시작 후 사용하면 됩니다.

------------------------

기존
jdbc:h2:~/test

변경
jdbc:h2:tcp://localhost/~/test

------------------------

 

- 최종 테스트

 

- 결과

댓글