프로그래밍/데이터베이스 관리

[MyBatis] XML 없이 MyBatis 동적 쿼리 만들기 (feat. Spring Boot)

이현성? 2023. 8. 24. 01:11

MyBatis🐦‍⬛

MyBatis는 데이터베이스 퍼시스턴스 프레임워크로 SQL 매핑 기술을 중심으로 기존의 JDBC를 대체하고 데이터베이스와의 상호작용을 좀 더 간편하고 유연하게 만들어주는 도구입니다. MyBatis는 XML 또는 어노테이션을 사용하여 SQL 매핑이 가능하고 동적으로 SQL 쿼리를 생성할 수 있는 빌더를 제공합니다.

 

Spring Boot 3는 XML없이 동작 가능하고 MyBatis도 3이상 버전부터 XML없이 어노테이션만 이용해 SQL 매핑이 가능해졌기 때문에 이번 글에서는 Spring Boot 3 환경에서 XML없이 MyBatis를 활용하여 동적 쿼리를 어떻게 작성하는지에 대해 알아보겠습니다.

Gradle🐘

먼저 Spring Boot 프로젝트에 필요한 MyBatis 관련 의존성을 설정합니다.

XML을 사용하면 안되기 때문에 Maven은 알아서 설정하세요.

// Kotlin DSL
implementation("org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.2")

// Groovy DSL
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.2'

@Mapper

동적 쿼리를 처리하기 위해 Mapper 인터페이스를 작성하고 @Mapper 어노테이션을 사용하여 등록해 줍니다.

@Getter
public class User {
    private int id;
    private String name;
    private String part;
}
@Mapper
public interface Mapper {
    @Insert("INSERT INTO user(name, part) values (#{user.name}, #{user.part})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int saveUser(@Param("user") User user);

    @Select("SELECT * FROM user")
    List<User> findUsers();

    @UpdateProvider(type = SqlBuilder.class, method = "buildUpdateUser")
    boolean updateUser(@Param("user") User user);

    @Delete("DELETE FROM user WHERE id = #{id}")
    boolean deleteUser(@Param("id") int id);
}

원래는 mapper.xml파일에 XML형식의 SQL mapper를 작성하고 application.propertiesapplication.yaml 파일에 MyBatis XML 경로 설정을 추가해줘야 하는 번거로움이 있었습니다.

 

하지만 3이상 버전부터 @Select, @Insert 등 어노테이션을 이용해 Mapper 인터페이스에 바로 SQL 쿼리를 작성할 수 있습니다.
매개변수를 받고 싶으면 @Param 어노테이션을 이용하면 되고 동적 바인딩을 하고 싶으면 #{ }를 사용하면 됩니다.
또한 @Options 어노테이션으로 auto increment된 PK를 매개변수로 넘긴 객체에 반환받을 수도 있습니다.
(int타입 return 값에 id가 반환되는 것이 아니라 매개변수로 넘긴 user의 id 필드에 auto increment PK가 들어 있음)

동적 쿼리 사용하기

이렇게 @Select, @Insert 등의 어노테이션만 이용하는 방법은 간편하다는 장점이 있지만 런타임에 쿼리를 만드는 동적 쿼리를 사용하기에는 어려움이 있습니다. 런타임에 동적으로 쿼리를 만들고 싶으면 @Select 대신 @SelectProvider 어노테이션을 이용하면 됩니다.

@UpdateProvider(type = SqlBuilder.class, method = "buildUpdateUser")
    boolean updateUser(@Param("user") User user);

요런 식으로 type에 동적 쿼리를 만들 클래스를 넣어주고 method에 쿼리를 리턴할 메서드 이름을 넣어줍니다. 그리고 동적 쿼리를 만들 클래스와 메서드를 구현해 주면 됩니다.

public class SqlBuilder {
    public static String buildUpdateUser(final @Param("user") User user) {
        return new SQL() {{
            UPDATE("user");
            LinkedList<String> sets = new LinkedList<>();
            if (user.getName() != null) {
                sets.add("name = #{user.name}");
            }
            if (user.getPart() != null) {
                sets.add("part = #{user.part}");
            }
            SET(sets.toArray(new String[0]));
            WHERE("id = #{user.id}");
        }}.toString();
    }
}

위의 예시처럼 PATCH 메서드 등으로 User의 일부 필드 업데이트 요청이 들어오는 경우 null인 필드는 SQL 쿼리에서 제외하는 등 런타임에 동적으로 쿼리를 작성할 수 있습니다. 쿼리를 String 형태로 반환하면 되지만 여러 줄의 String을 처리하면 가독성이 떨어지기 때문에 SQL()을 이용하는 것을 추천드립니다.

 

자세한 사용 방법은 공식문서에서 확인할 수 있습니다.
Mapper annotations
SQL() statement builder

결론

이 글에서는 XML 없이 MyBatis를 활용하여 Spring Boot 프로젝트에서 동적인 SQL 쿼리를 작성하는 방법을 소개했습니다. 물론 상황에 따라 XML을 사용하는 것이 더 나은 선택일 수도 있지만, XML 아예 모르는 사람도 Java 문법만으로 동적인 SQL 쿼리를 사용할 수 있다는 점이 정말 매력적인 것 같습니다.


물론 Spring Boot 3, MyBatis 버전 3이상을 사용해야 하지만 정말로 편한 것 같습니다.
(다들 Java 17 쓰시죠?🤷‍♂️)

 

제발 XML좀 그만 만났으면

 

 

mybatis – MyBatis 3 | Introduction

What is MyBatis? MyBatis is a first class persistence framework with support for custom SQL, stored procedures and advanced mappings. MyBatis eliminates almost all of the JDBC code and manual setting of parameters and retrieval of results. MyBatis can use

mybatis.org

 

 

[Spring Boot] 스프링부트에서 Mybatis 사용하기

먼저 Mybatis를 얘기하기 전에 JAVA의 ORM이 무엇이 있는지 어떤 것인지에 대해서 정리해보자. ORM(Object Relational Mapping)이란? ORM에서 Object는 객체지향 언어의 객체를 의미한다. Relational은 관계형 데이

devlog-wjdrbs96.tistory.com

 

 

마이바티스(MyBatis) 동적 쿼리 Java로 만들기.

스프링은 3.0 부터 Java Config를 지원하기 시작했고, 스프링 부트는 XML 설정 없이 동작 한다. (물론 여전히 XML 설정은 가능하다.) 마이바티스 또한, XML 설정 없이 Java 클래스만을 사용하여서, 동적 쿼

jason-moon.tistory.com