개발/Spring DB

MyBatis

Debin 2022. 6. 22.
반응형
 
본 게시글은 인프런 김영한 선생님 강의 스프링 DB 2편을 완강하고 배운 것을 남기고자 적은 포스팅입니다.
 

스프링 DB 2편 - 데이터 접근 활용 기술 - 인프런 | 강의

백엔드 개발에 필요한 DB 데이터 접근 기술을 활용하고, 완성할 수 있습니다. 스프링 DB 접근 기술의 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., - 강의 소개 | 인

www.inflearn.com

MyBatis 이전 파트에서는 이미 알고 있거나, 학습한 부분이 많아서 포스팅을 별도로 작성하지 않고 간단하게 요약만 하려고 합니다.

JdbcTemplate 요약

  • implementation 'org.springframework.boot:spring-boot-starter-jdbc'을 build.gradle 파일에 추가한다.
    별도의 추가 설정은 없다.
  • JdbcTemplate는 datasource가 필요하다. 즉 생성자를 통해 의존 관계를 주입 받으면 된다.
  • JdbcTemplate로는 동적 쿼리를 작성하기 까다롭다.
  • NamedParameterJdbcTemplate을 이용해서 이름 지정 파라미터 바인딩을 권장. 이 템플릿도 datasource가 필요하다.
    그냥 JdbcTemplate 사용할 때는 이것을 사용하면 될 것 같다.
  • 이름 지정 바인딩에서 자주 사용하는 파라미터 종류는 3가지가 있다.
  • Map, MapSqlParameterSource, BeanPropertySqlParameterSource 3가지가 있다.
  • MapSqlParameterSource, BeanPropertySqlParameterSource은 SqlParameterSource 인터페이스의 구현체다.
  • SimpleJdbcInsert를 관례상 많이 사용한다고 한다.
  • 스프링이 커넥션 풀과 Datasource 트랜잭션 매니저를 빈으로 자동 등록한다.

테스트

  • application.properties을 main과 test의 resources 디렉토리에 각각 2개 만들어서 진행해야한다.
  • 테스트를 진행한 데이터는 DB에 저장이되면 안된다. 따라서 테스트를 진행하고 트랜잭션을 커밋하지 않고 롤백을 해야한다.
  • @Transactional은 성공하면 커밋하고 실패하면 롤백을 하는 메커니즘을 가진다.
  • 하지만 테스트 코드에서는 테스트가 성공하면 롤백을 한다. 이를 통해 깔끔한 테스트를 진행할 수 있다.
  • application.properties에 테스트 설정을 하지 않으면 임베디드 모드 DB를 사용한다.

MyBatis

  • 요약은 아래와 같다.
  • JdbcTemplate보다 더 많은 기능을 제공하는 SQL Mapper이다.
  • 동적 쿼리를 편리하게 작성할 수 있다는 장점이 있다.
  • XML을 사용해 쿼리를 작성한다.

MyBatis는 좀 더 자세히 살펴보겠다. 먼저 MyBatis는 설정이 조금 필요하다. 아래와 같이 설정을 진행하자.

  1. implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0' 의존성을 build.gradle에 추가한다.
  2. application.properties에 다음과 같은 코드를 작성한다.
  #MyBatis
  mybatis.type-aliases-package=hello.itemservice.domain
  mybatis.configuration.map-underscore-to-camel-case=true
  logging.level.hello.itemservice.repository.mybatis=trace
 

설정에 대한 의미는 다음과 같다.

  • mybatis.type-aliases-package : 여기에 패키지 이름을 명시하면 XML에서 패키지 명을 생략할 수 있다.
  • mybatis.configuration.map-underscore-to-camel-case : 이 기능을 사용하면 언더바(스네이크 케이스)를 카멜 케이스로 자동 변경해주는 기능을 활성화 한다. 
  • logging.level.hello.itemservice.repository.mybatis=trace : MyBatis에서 실행되는 쿼리 로그를 확인할 수 있다.

이제 본격적인 사용법을 알아보자.

먼저 MyBatis를 사용하려면 @Mapper 애노테이션을 붙이고, 인터페이스로 코드를 작성해야 한다.

@Mapper //스프링 빈이라고 인식
public interface ItemMapper {
    void save(Item item);

    void update(@Param("id") Long id, @Param("updateParam")ItemUpdateDto updateParam);

    Optional<Item> findById(Long id);

    List<Item> findAll(ItemSearchCond itemSearch);
}

기능은 다음과 같다.

  • MyBatis 매핑 XML을 호출해주는 매퍼 인터페이스다.
  • @Mapper 애노테이션을 붙여주어야 한다. 그래야 MyBatis가 인식할 수 있다.
  • 이 인터페이스의 메서드를 호출하면 다음에 보이는 XML의 해당 SQL을 실행하고 결과를 돌려준다.
  • 인터페이스가 구현되는 방법은 아래에서 설명하겠다.

작성한 XML은 다음과 같다.

<?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="hello.itemservice.repository.mybatis.ItemMapper">
    <insert id="save" useGeneratedKeys="true" keyProperty="id">
        insert into item (item_name, price, quantity)
        values (#{itemName}, #{price}, #{quantity})
    </insert>
    <update id="update">
        update item
        set item_name=#{updateParam.itemName},
            price=#{updateParam.price},
            quantity=#{updateParam.quantity}
        where id = #{id}
    </update>
    <select id="findById" resultType="Item">
        select id, item_name, price, quantity
        from item
        where id = #{id}
    </select>
    <select id="findAll" resultType="Item">
        select id, item_name, price, quantity
        from item
        <where>
            <if test="itemName != null and itemName != ''">
                and item_name like concat('%',#{itemName},'%')
            </if>
            <if test="maxPrice != null">
                and price &lt;= #{maxPrice}
            </if>
        </where>
    </select>
</mapper>
  • namespace 태그에서 앞에서 만든 매퍼 인터페이스를 지정하면 된다.
  • #{} 문법을 사용한다. ?와 동일하다고 생각하면 된다.
  • useGeneratedKeys 는 데이터베이스가 키를 생성해 주는 IDENTITY 전략일 때 사용한다.
    keyProperty 는 생성되는 키의 속성 이름을 지정한다.
  • resultType 은 반환 타입을 명시하면 된다. 여기서는 결과를 Item 객체에 매핑한다.
  • 자바 코드에서 반환 객체가 하나이면 Item , Optional<Item> 과 같이 사용하면 되고, 반환 객체가 하나 이상이면 컬렉션을 사용하면 된다. 주로 List 를 사용한다.
  • 참고로 XML이므로 <는 태그를 정의할 때 사용한다. 따라서 특수문자를 &lt; 이렇게 사용해야 한다.
  • XML CDATA를 사용하면 편하게 부등호를 사용할 수 있다.

필자가 중요하게 생각한 내용은 작성했다. 더 자세하고 좋은 설명은 강의를 참고하면 좋을 것 같다.

 

그럼 이제 인터페이스만 작성했는데 어떻게 매퍼가 동작하는 것일까?

스프링 데이터 JPA에서도 배웠었는데, 바로 동적 프록시 기술을 사용한 것이다.

동적 프록시 로직
  1. 애플리케이션 로딩 시점에서 MyBatis 연동 모듈은 @Mapper가 붙어있는 인터페이스를 조사한다.
  2. 해당 인터페이스가 발견되면 동적 프록시 기술을 사용해서 ItemMapper 인터페이스의 구현체를 만든다.
  3. 생성된 구현체를 스프링 빈으로 등록한다.

Mapper 구현체는 예외 변환까지 처리해준다.

  • MyBatis에서 발생한 예외를 스프링 예외 추상화인 DataAccessException 에 맞게 변환해서 반환해준다.
    JdbcTemplate이 제공하는 예외 변환 기능을 여기서도 제공한다고 이해하면 된다.
  • 매퍼 구현체 덕분에 MyBatis 를 스프링에 편리하게 통합해서 사용할 수 있다.
  • 매퍼 구현체를 사용하면 스프링 예외 추상화도 함께 적용된다.
  • MyBatis 스프링 연동 모듈이 많은 부분을 자동으로 설정해주는데,
    데이터베이스 커넥션, 트랜잭션과 관련된 기능도 MyBatis와 함께 연동하고, 동기화해준다.

MyBatis의 최고 장점은 동적 쿼리 생성인데
if, choose(when, otherwise), trim (where, set), foreach 같은 문법으로 쉽게 작성할 수 있다.
더 깊고 자세한 내용은 강의를 참고하면 좋을 것 같다.

 

이상으로 포스팅을 마치겠습니다. 감사합니다.

반응형

댓글