19. 마이바티스 프레임워크

19. 마이바티스 프레임워크

마이바티스(MyBatis) 프레임워크의 개념과 설정, 동적 SQL 작성법을 다룬다.


1. 마이바티스란?

기존 JDBC 방식은 SQL이 자바 코드에 섞여 가독성이 떨어지고, 반복 코드가 많다. 마이바티스는 SQL을 XML로 분리하여 이 문제를 해결한다.

  기존 JDBC 흐름

  Connection 획득
       │
       ▼
  Statement 생성
       │
       ▼
  SQL문 전송
       │
       ▼
  결과 반환
       │
       ▼
  close

마이바티스의 특징

특징설명
SQL 분리SQL을 XML 파일에 작성하여 코드와 분리
자동 매핑실행 결과를 자바 빈즈 또는 Map으로 매핑
DataSource 지원데이터소스와 트랜잭션 처리 기능 내장
동적 SQL<if>, <choose>, <foreach> 등으로 조건부 SQL 구성

기존 JDBC vs 마이바티스

구분기존 JDBC마이바티스
SQL 위치자바 코드 안에 혼재XML 파일에 분리
결과 매핑ResultSet 수동 순회자동 매핑 (빈즈/Map)
파라미터 바인딩?와 인덱스 기반#{property} 이름 기반
코드량Connection~close 반복SQL과 매핑 설정만 작성

2. 마이바티스 설정 파일

설정 파일 구성

파일역할
config.xmlDB 연결 정보, 트랜잭션, 데이터소스 등 마이바티스 전역 설정
member.xmlSQL문을 정의하는 매퍼(mapper) 파일

두 파일 모두 src 패키지 아래에 위치해야 한다.

config.xml 예시

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/
   mybatis-3-config.dtd">
<configuration>
    <!-- VO 클래스 별칭 설정 -->
    <typeAliases>
        <typeAlias type="com.spring.vo.MemberVO"
            alias="memberVO" />
    </typeAliases>

    <!-- DB 연결 설정 -->
    <environments default="development">
        <environment id="development">
            <transactionManager
                type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver"
                    value="oracle.jdbc.driver
                           .OracleDriver" />
                <property name="url"
                    value="jdbc:oracle:thin:
                           @localhost:1521:XE" />
                <property name="username"
                    value="scott" />
                <property name="password"
                    value="tiger" />
            </dataSource>
        </environment>
    </environments>

    <!-- 매퍼 파일 등록 -->
    <mappers>
        <mapper resource="member.xml" />
    </mappers>
</configuration>

member.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="mapper.member">

    <!-- 전체 회원 조회 -->
    <select id="selectAllMembers"
        resultType="memberVO">
        <![CDATA[
            SELECT * FROM t_member
            ORDER BY joinDate DESC
        ]]>
    </select>

    <!-- 회원 추가 -->
    <insert id="insertMember"
        parameterType="memberVO">
        INSERT INTO t_member
            (id, pwd, name, email)
        VALUES
            (#{id}, #{pwd},
             #{name}, #{email})
    </insert>

    <!-- 회원 삭제 -->
    <delete id="deleteMember"
        parameterType="String">
        DELETE FROM t_member
        WHERE id = #{id}
    </delete>

</mapper>
SQL문에 >, <, <=, >= 같은 연산자를 사용할 때는 XML 특수 문자로 인식되므로 반드시 <![CDATA[...]]> 태그 안에 작성해야 한다.

3. SqlSession 클래스의 주요 메서드

SqlSession은 마이바티스에서 SQL을 실행하는 핵심 객체다.

메서드기능
selectList(id)select 실행 후 여러 레코드를 List로 반환
selectList(id, 조건)조건을 전달하며 select 실행
selectOne(id)select 실행 후 단건 결과 반환
selectOne(id, 조건)조건을 전달하며 단건 조회
selectMap(id, 조건)select 실행 후 Map으로 반환
insert(id, obj)obj 값으로 insert 실행
update(id, obj)obj 값으로 update 실행
delete(id, obj)obj 값으로 delete 실행

DAO에서 SqlSession 사용

public class MemberDAO {

    private static SqlSessionFactory factory;

    // SqlSessionFactory 초기화
    static {
        String resource = "config.xml";
        try {
            Reader reader = Resources
                .getResourceAsReader(resource);
            factory = new SqlSessionFactoryBuilder()
                .build(reader);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 전체 회원 조회
    public List<MemberVO> selectAllMembers() {
        SqlSession session =
            factory.openSession();
        List<MemberVO> list =
            session.selectList(
                "mapper.member"
                + ".selectAllMembers");
        session.close();
        return list;
    }

    // 회원 추가
    public int insertMember(MemberVO vo) {
        SqlSession session =
            factory.openSession();
        int result = session.insert(
            "mapper.member.insertMember", vo);
        session.commit();
        session.close();
        return result;
    }
}
  SqlSession 동작 흐름

  SqlSessionFactory
       │
       ▼
  openSession()
       │
       ▼
  ┌──────────────────┐
  │   SqlSession     │
  │                  │
  │ selectList(id)   │
  │ insert(id, obj)  │
  │ update(id, obj)  │
  │ delete(id, obj)  │
  └───────┬──────────┘
          │
          ▼
  매퍼 XML에서 SQL 조회
          │
          ▼
  DBMS로 SQL 실행
          │
          ▼
  결과 → VO/List/Map
insert, update, delete 실행 후에는 반드시 **session.commit()**을 호출해야 DB에 반영된다. selectList/selectOne은 조회만 수행하므로 commit이 필요 없다.

4. 동적 SQL문

마이바티스는 조건에 따라 SQL을 동적으로 구성하는 태그를 제공한다. JSTL과 XML 기반으로 작성한다.

태그역할비유
<if>조건이 참이면 SQL 추가Java if
<choose>여러 조건 중 하나 선택Java switch
<foreach>컬렉션을 순회하며 SQL 생성Java for
<where>조건이 있으면 WHERE절 추가
<sql> / <include>SQL 조각 재사용메서드 추출

5. <if> 태그

<where> 태그 안에서 사용하며, 조건이 참일 때 SQL 구문을 추가한다.

<select id="searchMember"
    parameterType="memberVO"
    resultType="memberVO">
    SELECT * FROM t_member
    <where>
        <if test="name != null
                  and name != ''">
            name = #{name}
        </if>
        <if test="email != null
                  and email != ''">
            AND email = #{email}
        </if>
    </where>
</select>

<where> 태그는 내부 조건이 하나라도 참이면 WHERE를 추가하고, 첫 번째 조건의 불필요한 AND/OR를 자동 제거한다.

동작 예시

nameemail생성되는 SQL
“홍길동”nullWHERE name = '홍길동'
nulla@b.comWHERE email = 'a@b.com'
“홍길동”a@b.comWHERE name = '홍길동' AND email = 'a@b.com'
nullnull(WHERE절 없음 — 전체 조회)

6. <choose> 태그

자바의 switch문처럼 여러 조건 중 하나만 적용한다.

<select id="searchByCondition"
    parameterType="map"
    resultType="memberVO">
    SELECT * FROM t_member
    <where>
        <choose>
            <when test="searchType == 'name'">
                name LIKE '%'
                    || #{keyword} || '%'
            </when>
            <when test="searchType == 'email'">
                email LIKE '%'
                    || #{keyword} || '%'
            </when>
            <otherwise>
                id = #{keyword}
            </otherwise>
        </choose>
    </where>
</select>
<otherwise>는 생략할 수 있다. 모든 <when> 조건이 거짓이면 아무 조건도 추가되지 않는다.

7. <foreach> 태그

컬렉션을 순회하며 SQL을 반복 생성한다. IN절이나 다중 INSERT에 활용된다.

속성

속성설명
collection전달받은 인자 (list 또는 array)
item반복 시 현재 요소를 참조하는 변수명
index현재 반복 인덱스 (0부터 시작)
open구문 시작 시 추가할 기호
close구문 종료 시 추가할 기호
separator반복 사이에 추가할 구분자

IN절 예시

<select id="selectByIds"
    parameterType="map"
    resultType="memberVO">
    SELECT * FROM t_member
    WHERE id IN
    <foreach item="item"
        collection="idList"
        open="(" close=")"
        separator=",">
        #{item}
    </foreach>
</select>

생성되는 SQL:

SELECT * FROM t_member
WHERE id IN ('kim', 'lee', 'park')

다중 INSERT (오라클)

오라클에서는 여러 INSERT를 동시에 실행하면 오류가 발생한다. INSERT ALL ... SELECT * FROM DUAL 형식을 사용해야 한다.

<insert id="insertMembers"
    parameterType="map">
    <foreach item="item"
        collection="list"
        open="INSERT ALL"
        separator=" "
        close="SELECT * FROM DUAL">
        INTO t_member
            (id, pwd, name, email)
        VALUES
            (#{item.id}, #{item.pwd},
             #{item.name}, #{item.email})
    </foreach>
</insert>
MySQL은 VALUES (), (), () 형식으로 다중 INSERT가 가능하지만, 오라클은 INSERT ALL ... SELECT * FROM DUAL 패턴을 사용해야 한다. DB 벤더에 따라 구문이 다르므로 주의하자.

8. <sql> 태그와 <include> 태그

반복되는 SQL 조각을 <sql>로 정의하고, <include>로 재사용한다.

<!-- SQL 조각 정의 -->
<sql id="memberColumns">
    id, pwd, name, email, joinDate
</sql>

<!-- 재사용 -->
<select id="selectAllMembers"
    resultType="memberVO">
    SELECT
        <include refid="memberColumns" />
    FROM t_member
</select>

<select id="selectMember"
    parameterType="String"
    resultType="memberVO">
    SELECT
        <include refid="memberColumns" />
    FROM t_member
    WHERE id = #{id}
</select>

여러 매퍼 파일에서 공통 SQL 조각을 사용하려면 네임스페이스를 포함하여 참조한다.

<include
    refid="mapper.common.memberColumns" />

오라클에서 마이바티스로 LIKE 검색할 때는 % 기호와 조건 값 사이에 **|| (연결 연산자)**를 사용해야 한다.

name LIKE '%' || #{name} || '%'

9. 스프링과 마이바티스 연동

실무에서는 마이바티스를 단독으로 사용하기보다 스프링과 연동하여 사용한다.

연동 구조

  스프링 + 마이바티스 구조

  Controller
       │
       ▼
  Service
       │
       ▼
  ┌──────────────────┐
  │  DAO             │
  │  (SqlSession 주입)│
  └───────┬──────────┘
          │
          ▼
  ┌──────────────────┐
  │  매퍼 XML        │
  │  (SQL 정의)      │
  └───────┬──────────┘
          │
          ▼
      DataSource → DB

스프링 설정

<!-- SqlSessionFactory 빈 등록 -->
<bean id="sqlSessionFactory"
  class="org.mybatis.spring
         .SqlSessionFactoryBean">
    <property name="dataSource"
        ref="dataSource" />
    <property name="configLocation"
        value="classpath:config.xml" />
</bean>

<!-- SqlSessionTemplate 빈 등록 -->
<bean id="sqlSession"
  class="org.mybatis.spring
         .SqlSessionTemplate">
    <constructor-arg
        ref="sqlSessionFactory" />
</bean>

DAO에서 사용

@Repository("memberDAO")
public class MemberDAOImpl
        implements MemberDAO {

    @Autowired
    private SqlSession sqlSession;

    @Override
    public List<MemberVO> selectAllMembers() {
        return sqlSession.selectList(
            "mapper.member.selectAllMembers");
    }

    @Override
    public int insertMember(MemberVO vo) {
        return sqlSession.insert(
            "mapper.member.insertMember", vo);
    }
}
스프링과 연동하면 SqlSessionTemplate트랜잭션 관리세션 자동 close를 처리해 준다. 직접 commit()이나 close()를 호출할 필요가 없다.

요약

개념한 줄 정리
마이바티스SQL을 XML로 분리하여 관리하는 Persistence 프레임워크
SqlSessionSQL 실행과 트랜잭션을 담당하는 핵심 객체
config.xmlDB 연결, 별칭, 매퍼 등록 등 전역 설정
매퍼 XMLSQL문을 정의하는 파일 (select, insert, update, delete)
동적 SQL<if>, <choose>, <foreach> 등으로 조건부 SQL 구성
<sql> / <include>SQL 조각을 정의하고 재사용

JdbcTemplate vs 마이바티스

구분JdbcTemplate마이바티스
SQL 위치자바 코드 안 (String)XML 파일에 분리
파라미터 바인딩? + 순서 기반#{property} 이름 기반
결과 매핑RowMapper 직접 구현resultType으로 자동 매핑
동적 SQL자바 코드로 조건 분기XML 태그(<if>, <choose>)로 구성
학습 비용낮음중간 (XML 태그 학습 필요)
적합한 상황단순 CRUD복잡한 SQL, 검색 조건이 다양한 경우