본문 바로가기

JAVA

MyBatis Dynamic SQL 완전 정리: 타입 안전하게 SQL을 생성하는 방법

728x90
반응형
728x170

이 글은 MyBatis Dynamic SQL의 개념과 필요성, 그리고 실제 사용 방법을 정리한 기술 블로그입니다.
SQL을 문자열로 직접 작성하다 보면 문법 오류나 파라미터 바인딩 실수로 인해 런타임 오류를 겪는 경우가 많습니다. MyBatis Dynamic SQL은 이러한 문제를 줄이기 위해 등장한 라이브러리로, 데이터베이스 구조를 기반으로 타입 안전한 SQL 생성을 가능하게 합니다.
이 글에서는 MyBatis Dynamic SQL의 기본 개념부터 데이터베이스 객체 정의, SELECT 및 CRUD 쿼리 작성 방법까지 예제와 함께 살펴봅니다.

반응형

MyBatis Dynamic SQL이란?

MyBatis Dynamic SQL은 타입 세이프한 방식으로 SQL을 생성할 수 있도록 지원하는 라이브러리입니다.
SQL 문법과 파라미터 바인딩을 코드 수준에서 검증할 수 있으며, 데이터베이스 테이블과 컬럼을 자바 클래스 형태로 정의해 컴파일러를 통해 오류 가능성을 줄일 수 있습니다.

즉, SQL 문자열을 직접 작성하는 방식이 아니라,
데이터베이스 구조를 코드로 표현하고 이를 기반으로 SQL을 조립하는 방식입니다.


MyBatis Dynamic SQL 의존성 설정

MyBatis Dynamic SQL을 사용하기 위해서는 라이브러리를 프로젝트에 추가해야 합니다.
작성 시점 기준 최신 버전은 1.5.2입니다.

Maven 의존성 설정 예시

<dependency>
    <groupId>org.mybatis.dynamic-sql</groupId>
    <artifactId>mybatis-dynamic-sql</artifactId>
    <version>1.5.2</version>
</dependency>

해당 의존성을 추가하면 바로 MyBatis Dynamic SQL을 사용할 수 있습니다.


데이터베이스 객체(Database Objects) 정의

MyBatis Dynamic SQL은 데이터베이스 테이블과 컬럼을 자바 클래스와 필드로 표현합니다.
이러한 객체들은 SqlTable 또는 이를 확장한 클래스를 상속받아 작성됩니다.

테이블 객체 정의

public class User extends SqlTable {

    public User() {
        super("users");
    }
}
  • "users"는 실제 데이터베이스의 테이블 이름입니다.
  • 이 클래스는 users 테이블을 자바 코드로 표현합니다.

컬럼 정의

public class User extends AliasableSqlTable<User> {
    public final SqlColumn<Integer> userId = column("user_id");
    public final SqlColumn<String> userName = column("username");
}
  • 각 컬럼은 SqlColumn<T> 타입으로 정의됩니다.
  • 컬럼 타입과 자바 타입이 연결되어 SQL 작성 시 타입 안전성이 확보됩니다.
  • SQL 생성 시 외부에서 참조할 수 있도록 public으로 선언합니다.

SQL 생성 흐름 이해하기

MyBatis Dynamic SQL은 SqlBuilder 클래스의 정적 메서드를 사용해 SQL 생성을 시작합니다.

SQL 모델 생성

SelectModel model = SqlBuilder.countFrom(user)
  .build();
  • 생성할 SQL의 유형을 먼저 지정합니다.
  • build() 호출 시 SQL 모델 객체가 생성됩니다.

SQL 렌더링

SelectStatementProvider sqlStatement =
  SqlBuilder.select(user.allColumns())
    .from(user)
    .build()
    .render(RenderingStrategies.SPRING_NAMED_PARAMETER);
  • render()를 호출하면 실제 실행 가능한 SQL과 파라미터 정보가 생성됩니다.
  • MyBatis3 또는 Spring 환경에 맞는 렌더링 전략을 선택할 수 있습니다.

SQL과 바인딩 파라미터 확인

String sql = sqlStatement.getSelectStatement();
Map<String, Object> binds = sqlStatement.getParameters();
  • SQL 문자열과 파라미터를 분리해 관리할 수 있습니다.
  • 해당 값들을 실제 DB 호출 시 전달해 사용합니다.

SELECT 문 작성 방법

기본 SELECT 쿼리

SelectStatementProvider sql = SqlBuilder.select(user.allColumns())
  .from(user)
  .build()
  .render(RenderingStrategies.SPRING_NAMED_PARAMETER);
  • select, selectDistinct, countFrom 등 다양한 시작 메서드를 제공합니다.
  • 조회 대상 컬럼은 개별 컬럼 또는 allColumns()로 지정할 수 있습니다.

집계 함수 사용

count, max, sum 등의 집계 함수도 일반 컬럼과 동일한 방식으로 사용할 수 있습니다.


WHERE 절 작성 방법

단일 조건

SelectStatementProvider sql = SqlBuilder.select(user.allColumns())
  .from(user)
  .where(user.userName, SqlBuilder.isEqualTo("baeldung"))
  .build()
  .render(RenderingStrategies.SPRING_NAMED_PARAMETER);
  • 컬럼 타입에 맞는 비교 연산만 허용되어 타입 안정성이 보장됩니다.
  • 생성되는 SQL 예시는 다음과 같습니다.
SELECT * FROM users WHERE username = :p1

복합 조건 (AND / OR)

SelectStatementProvider sql = SqlBuilder.select(user.allColumns())
  .from(user)
  .where(user.userName, SqlBuilder.isEqualTo("baeldung"))
  .or(user.userId, SqlBuilder.isGreaterThan(5))
  .build()
  .render(RenderingStrategies.SPRING_NAMED_PARAMETER);
  • 복잡한 조건도 메서드 체이닝으로 명확하게 표현할 수 있습니다.

JOIN 사용 방법

여러 테이블을 함께 조회해야 하는 경우 join() 메서드를 사용합니다.

SelectStatementProvider sql = SqlBuilder.select(post.allColumns())
  .from(post)
  .join(user).on(user.userId, SqlBuilder.equalTo(post.posterId))
  .build()
  .render(RenderingStrategies.SPRING_NAMED_PARAMETER);

생성되는 SQL은 다음과 같습니다.

SELECT posts.* FROM posts JOIN users ON users.user_id = posts.poster_id

지원하는 JOIN 유형

  • join() : INNER JOIN
  • leftJoin() : LEFT JOIN
  • rightJoin() : RIGHT JOIN
  • fullJoin() : FULL JOIN

INSERT, UPDATE, DELETE 문 작성

DELETE 문

DeleteStatementProvider sql = SqlBuilder.deleteFrom(user)
  .where(user.userId, isEqualTo(1))
  .build()
  .render(RenderingStrategies.SPRING_NAMED_PARAMETER);

UPDATE 문

UpdateStatementProvider sql = SqlBuilder.update(user)
  .set(user.userName).equalTo("Baeldung")
  .where(user.userId, isEqualTo(1))
  .build()
  .render(RenderingStrategies.SPRING_NAMED_PARAMETER);

INSERT 문

GeneralInsertStatementProvider sql = SqlBuilder.insertInto(user)
  .set(user.userId).toValue(2)
  .set(user.userName).toValue("Baeldung")
  .build()
  .render(RenderingStrategies.SPRING_NAMED_PARAMETER);
  • INSERT 문은 WHERE 절을 지원하지 않습니다.
  • 모든 SQL은 실행용 SQL과 바인딩 파라미터를 분리해 제공합니다.

728x90

MyBatis Dynamic SQL은 SQL을 코드 기반으로 안전하게 관리할 수 있도록 돕는 라이브러리입니다.
컴파일 시점에 오류를 줄이고, 복잡한 쿼리를 명확한 구조로 표현할 수 있다는 점이 가장 큰 장점입니다.

문자열 기반 SQL 관리에 한계를 느끼고 있다면,
MyBatis Dynamic SQL은 SQL 품질과 유지보수성을 함께 개선할 수 있는 하나의 대안이 될 수 있습니다.

300x250

https://www.baeldung.com/java-mybatis-dynamic-sql?fbclid=IwY2xjawOuQZdleHRuA2FlbQIxMQBzcnRjBmFwcF9pZBAyMjIwMzkxNzg4MjAwODkyAAEeiKJcNdmZ-eMQpob_r5P8VcKKrJtkx5f4NtifTzfuKiU4cndsO8HnF9og8to_aem_oBzl0XDXv8-4nSMDP85i9g

728x90
반응형
그리드형