Spring Boot 용 플러그인이 포함되어 있기 때문에, 이를 사용하면 간단하게 연계할 수 있다.

DB 테이블

test_table

idvalue
1hoge
2fuga
3piyo

폴더 구성

├── build.gradle
├── src/main/
│   └── java/
│   └── sample/mybatis/springboot/
│       └── Main.java
│       └── TestTableMapper.java
└── resources/
    └── application.properties
    └── mybatis-config.xml
    └── TestTableMapper.xml

소스 코드

build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.3.1.RELEASE'
    }
}

apply plugin: 'java'
apply plugin: 'spring-boot'

sourceCompatibility = '1.8'
targetCompatibility = '1.8'
compileJava.options.encoding = 'UTF-8'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.springframework.boot:spring-boot-starter'
    // MyBatis의 SpringBoot 용 의존 라이브러리 파일을 포함한다.
    compile 'org.mybatis.spring.boot:mybatis-spring-boot-starter:1.0.0'
    compile 'mysql:mysql-connector-java:5.1.38'
}

application.properties

# MyBatis 설정 파일을 로드한다.
mybatis.config=mybatis-config.xml

# 데이터 소스 설정한다.
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=test
spring.datasource.password=test
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

mybatis-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>
    <!-- 데이터 소스 관리는 Spring Boot에서 하기 때문에 여기에 작성하지 않는다. -->
  <mappers>
    <mapper resource="TestTableMapper.xml"/>
  </mappers>
</configuration>

TestTableMapper.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="sample.mybatis.springboot.TestTableMapper">

  <select id="selectTest" resultType="map">
    select * from test_table
  </select>
</mapper>

TestTableMapper.java

package sample.mybatis.springboot;

import java.util.List;
import java.util.Map;

public interface TestTableMapper {

    List<Map<String, Object>> selectTest();
}

Main.java

package sample.mybatis.springboot;

import java.io.IOException;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Main {

    public static void main(String[] args) throws IOException {
        try (ConfigurableApplicationContext ctx = SpringApplication.run(Main.class, args)) {
            Main m = ctx.getBean(Main.class);
            m.method();
        }
    }

    @Autowired
    private SqlSessionTemplate sqlSession;
    @Autowired
    private TestTableMapper mapper;

    public void method() throws IOException {
        System.out.println("[SqlSessionTemplate]");
        this.sqlSession
            .selectList("sample.mybatis.springboot.TestTableMapper.selectTest")
            .forEach(System.out::println);

        System.out.println("[TestTableMapper]");
        this.mapper
            .selectTest()
            .forEach(System.out::println);
    }
}

실행결과

[SqlSessionTemplate]
{id=1, value=hoge}
{id=2, value=fuga}
{id=3, value=piyo}

[TestTableMapper]
{id=1, value=hoge}
{id=2, value=fuga}
{id=3, value=piyo}

설명

  • Spring Boot에서 MyBatis를 사용하는 경우에는 mybatis-spring-boot-starter를 의존성에 추가한다.
  • 다음에는 Spring Boot 설정 파일 (application.properties)에서 mybatis.config라는 이름으로 MyBatis 설정 파일을 지정한다.
  • 데이터 소스는 Spring Boot에서 관리해 주기 때문에, Spring Boot의 설정에서 작성하고 MyBatis에서는 따로 작성하지 않는다.
  • SqlSession에 액세스하려면 SqlSessionTemplate을 @Autowired에 주입하면 된다.
    • SqlSessionTemplate의 API는 SqlSession과 같다.
    • SqlSession과 달리 thread가 안전적이기 때문에 다른 스레드나 DAO에서 사용해도 문제 없다.
  • Mapper 인터페이스를 정의를 해두면, @Autowired에 주입할 수 있다.
    • Spring에 스캔되는 위치에 인터페이스를 넣어 두어야 한다.
    • Main 클래스를 @MapperScan에서 어노테이션하면, 모든 패키지 Mapper 인터페이스를 검색할 수 있다 (예 : @MapperScan( "foo.bar")).
    • 이쪽도 thread로 안전한 인스턴스가 주입되기 때문에 다른 스레드나 DAO에서 사용하여도 무방하다.


'MyBatis' 카테고리의 다른 글

[MyBatis] Spring Boot와 연계  (0) 2017.12.31
[MyBatis] 프로그램에서 SQL을 동적으로 생성  (0) 2017.12.31
[MyBatis] 동적 SQL  (0) 2017.12.31
[MyBatis] Mapper  (0) 2017.12.31
[MyBatis] 배치(batch) 갱신  (0) 2017.12.31
[MyBatis] 삭제 DELETE  (0) 2017.12.31

MyBatis 어노테이션을 사용하여 SQL을 정의하는 방법이 제공된다.

그러나 문자열 연결에서 SQL을 조립하고 쉼표 구분이라든지 AND, OR 구분 등 주의해야 하는 세세한 것들이 여러 가지가 있다.

그 부분에 대해 귀찮은 부분을 감추는 API를 제공하고 있다.

소스 코드

sample_mapper.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="sample.mybatis.TestTableMapper"> <!-- Mapper을 namespace에 지정 -->
</mapper>

TestTableMapper.java

package sample.mybatis;

import java.util.List;

import org.apache.ibatis.annotations.SelectProvider;

// Mapper 인터페이스로 만든다
public interface TestTableMapper {
    // @SelectProvider으로 SQL을 생성하는 클래스 메소드를 설정한다
    @SelectProvider(type=TestTableSqlProvider.class, method="getSelectTestSql")
    List<TestTable> selectTest();
}

TestTableSqlProvider.java

package sample.mybatis;

import org.apache.ibatis.jdbc.SQL;

// SQL을 생성하는 클래스
public class TestTableSqlProvider {

    // SQL을 생성하는 메소드
    public String getSelectTestSql() {
        // SQL 클래스를 사용하여 SQL을 생성한다.
        SQL sql = new SQL() {{ // 익명의 클래스 생성
            SELECT("id, hoge_value");
            SELECT("fuga_value");
            SELECT("piyo_value");
            FROM("test_table");
        }};

        return sql.toString();
    }
}

Main.java

package sample.mybatis;

import java.io.InputStream;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Main {

    public static void main(String[] args) throws Exception {
        try (InputStream in = Main.class.getResourceAsStream("/mybatis-config.xml")) {
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

            try (SqlSession session = factory.openSession()) {
                TestTableMapper mapper = session.getMapper(TestTableMapper.class);
                mapper.selectTest();
            }
        }
    }
}

실행 결과

[DEBUG] s.m.T.selectTest - ==>  Preparing: SELECT id, hoge_value, fuga_value, piyo_value FROM test_table WHERE (hoge_value is not null) 
[DEBUG] s.m.T.selectTest - ==> Parameters: 

설명

  • Mapper의 메소드를 @SelectProvider에서 어노테이션을 지정한다.
    • type에 SQL을 생성하는 클래스로 하고, method에 SQL을 생성하는 메소드의 이름을 지정한다.
    • INSERT 또는 UPDATE에는 @InsertProvider과 @UpdateProvider가 있다.
  • SQL 생성에는 org.apache.ibatis.jdbc.SQL 클래스를 사용한다.
  • SQL 클래스를 익명 클래스로 new하여 인스턴스 초기화 블록에서 SELECT()와 FROM() 메소드를 사용하여 SQL을 생성한다.
    • 각 인수는 문자열에서 SQL의 항목을 전달한다.
    • 이때 쉼표 구분 등은 필요에 따라 추가되기도 한다.
  • 생성된 SQL 인스턴스의 toString() 메소드에서 생성한 SQL을 문자열로 검색할 수 있다.



각 메소드의 사용법에 대해

SELECT

new SQL() {{
    SELECT("foo");
    SELECT("bar");
    SELECT("fizz, buzz");
    FROM("foo_table");
}};
SELECT foo, bar, fizz, buzz FROM foo_table 
  • 연속하여 작성하면, 각 항목을 쉼표로 마음대로 구분된다.
  • 명시적으로 쉼표로 구분된 문자열 전달도 된다.
  • 끝에 불필요한 쉼표가 있는 경우, 제거해 주지 않는다.

FROM

new SQL() {{
    SELECT("*");
    FROM("foo_table");
    FROM("bar_table");
}};
SELECT * FROM foo_table, bar_table 
  • FROM을 연속하여 작성할 경우, 쉼표 구분으로 FROM 절이 열거된다.

WHERE

new SQL() {{
    SELECT("*");
    FROM("foo_table");
    WHERE("foo = ?");
    WHERE("bar = ?");
    AND();
    WHERE("fizz = ?");
    WHERE("buzz = ?");
    OR();
    WHERE("hoge = ?");
    WHERE("fuga = ?");
}};
SELECT *
  FROM foo_table
 WHERE (
       foo = ?
       AND bar = ?
 ) AND (
       fizz = ?
       AND buzz = ?
 )  OR (
       hoge = ?
       AND fuga = ?
 ) 
  • WHERE() 메소드로 WHERE 절을 생성할 수 있다.
  • WHERE() 메소드를 연속하여 작성하면 AND 조건으로 연결된다.
  • AND() 및 OR() 메소드를 사용하면 AND, OR로 연결할 수 있다.

INNER_JOIN

new SQL() {{
    SELECT("*");
    FROM("foo_table");
    INNER_JOIN("bar_table on bar_table.id = foo_table.bar_id");
    INNER_JOIN("fizz_table on fizz_table.id = bar_table.fizz_id");
}};
    SELECT *
      FROM foo_table
INNER JOIN bar_table
        on bar_table.id = foo_table.bar_id
INNER JOIN fizz_table
        on fizz_table.id = bar_table.fizz_id 
  • INNER_JOIN() 메소드으로 INNER JOIN 절을 추가할 수 있다.
  • 조인 조건 문자열( on~)을 작성해야 한다.

ORDER_BY

new SQL() {{
    SELECT("*");
    FROM("foo_table");
    ORDER_BY("foo");
    ORDER_BY("bar desc");
}};
SELECT * FROM foo_table ORDER BY foo, bar desc 
  • ORDER_BY() 메소드로 ORDER BY 절을 생성할 수 있다.
  • 연속하여 작성되면 자동으로 쉼표로 구분된다.

GROUP_BY

new SQL() {{
    SELECT("foo, bar");
    FROM("foo_table");
    GROUP_BY("foo");
    GROUP_BY("bar");
}};
SELECT foo, bar FROM foo_table GROUP BY foo, bar 
  • GROUP_BY() 메소드로 GROUP BY 절을 생성할 수 있다.
  • 연속하여 작성되면 자동으로 쉼표로 구분된다.

HAVING

new SQL() {{
    SELECT("foo, count(*)");
    FROM("foo_table");
    GROUP_BY("foo");
    HAVING("0 < count(*)");
    HAVING("count(*) < 100");
}};
  SELECT foo
        ,count(*)
    FROM foo_table
GROUP BY foo
  HAVING (
         0 < count(foo)
         AND count(foo) < 100
  )
  • HAVING() 메소드로 HAVING 절을 생성할 수 있다.
  • WHERE()와 같은 동작을 한다 (연속하여 작성하면 AND로 연결된다).

INSERT_INTO, VALUES

new SQL() {{
    INSERT_INTO("foo_table");
    VALUES("foo_value", "#{foo_value}");
    VALUES("fizz_value, buzz_value", "#{fizz_value}, #{buzz_value}");
}};
INSERT INTO foo_table (foo_value, fizz_value, buzz_value) VALUES (?, ?, ?) 
  • INSERT_INTO() 메소드로 INSERT 문을 생성할 수 있다.
  • VALUES() 메소드로 등록할 항목을 정의할 수 있다.
    • 첫 번째 인수에는 설정하는 항목의 이름을 작성하고
    • 두 번째 인수에는 VALUES 절에서 지정한 값을 전달한다.
    • 여러 설명하면 자동으로 쉼표로 구분된다.

UPDATE, SET

new SQL() {{
    UPDATE("foo_table");
    SET("foo_value = #{foo_value}");
    SET("bar_value = #{bar_value}");
    WHERE("id = #{id}");
}};
UPDATE foo_table SET foo_value = ?, bar_value = ? WHERE (id = ?)
  • UPDATE() 메소드에서 UPDATE 문을 생성할 수 있다.
  • SET() 메소드에서 SET 절을 생성할 수 있다.
  • 연속하여 작성되면 자동으로 쉼표로 구분된다.

DELETE_FROM

new SQL() {{
    DELETE_FROM("foo_table");
    WHERE("id = #{id}");
}};
DELETE FROM foo_table WHERE (id = ?) 
  • DELETE_FROM() 메소드로 DELETE 문을 생성할 수 있다.



'MyBatis' 카테고리의 다른 글

[MyBatis] Spring Boot와 연계  (0) 2017.12.31
[MyBatis] 프로그램에서 SQL을 동적으로 생성  (0) 2017.12.31
[MyBatis] 동적 SQL  (0) 2017.12.31
[MyBatis] Mapper  (0) 2017.12.31
[MyBatis] 배치(batch) 갱신  (0) 2017.12.31
[MyBatis] 삭제 DELETE  (0) 2017.12.31

조건에 맞는 SQL을 동적(Dynamic)으로 생성할 수 있다.


if

DB 테이블

test_table

idstring_valuenumber_value
1hoge100
2hoge200
3fuga300
4piyo400

소스 코드

sample_mapper.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="sample.mybatis">

  <select id="selectTest" resultType="sample.mybatis.TestTable">
    select *
      from test_table
     where string_value = 'hoge'
     <if test="numberValue != null"> <!-- if 태그에서 조건 분기 -->
       and number_value = #{numberValue}
     </if>
  </select>
</mapper>

Main.java

package sample.mybatis;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Main {

    public static void main(String[] args) throws Exception {
        try (InputStream in = Main.class.getResourceAsStream("/mybatis-config.xml")) {
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

            try (SqlSession session = factory.openSession()) {
                session
                    .selectList("sample.mybatis.selectTest") // 매개 변수 미설정
                    .forEach(System.out::println);

                Map<String, Object> param = new HashMap<>();
                param.put("numberValue", 100);

                session
                    .selectList("sample.mybatis.selectTest", param) // 매개 변수 설정
                    .forEach(System.out::println);
            }
        }
    }
}

실행 결과

[DEBUG] s.m.selectTest  - ==>  Preparing: select * from test_table where string_value = 'hoge' 
[DEBUG] s.m.selectTest  - ==> Parameters: 
[DEBUG] s.m.selectTest  - <==      Total: 2
TestTable [id=1, stringValue=hoge, numberValue=100]
TestTable [id=2, stringValue=hoge, numberValue=200]

[DEBUG] s.m.selectTest  - ==>  Preparing: select * from test_table where string_value = 'hoge' and number_value = ? 
[DEBUG] s.m.selectTest  - ==> Parameters: 100(Integer)
[DEBUG] s.m.selectTest  - <==      Total: 1
TestTable [id=1, stringValue=hoge, numberValue=100]

설명

  • <if> 태그를 사용하여 조건이 충족된 경우에만 SQL을 추가 시키거나 삭제할 수 있게 된다.
  • test 속성에서 조건식을 기술한다.
    • 이 가운데는 검색 조건에 전달할 매개 변수의 값을 참조할 수 있다.
    • AND나 OR 조건을 작성할 때, and, or를 사용한다 ("&&", "||"가 아니다!).


choose, when, otherwise

DB 테이블

test_table

idvalue
1hoge
2
3piyo

소스 코드

sample_mapper.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="sample.mybatis">

  <select id="selectTest" resultType="sample.mybatis.TestTable">
    select *
      from test_table
    <choose>
      <when test="value == null">
        where value is null
      </when>
      <otherwise>
        where value = #{value}
      </otherwise>
    </choose>
  </select>
</mapper>

Main.java

package sample.mybatis;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Main {

    public static void main(String[] args) throws Exception {
        try (InputStream in = Main.class.getResourceAsStream("/mybatis-config.xml")) {
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

            try (SqlSession session = factory.openSession()) {
                TestTable testTable = session.selectOne("sample.mybatis.selectTest");
                System.out.println(testTable);

                Map<String, Object> param = new HashMap<>();
                param.put("value", "hoge");

                testTable = session.selectOne("sample.mybatis.selectTest", param);
                System.out.println(testTable);
            }
        }
    }
}

실행 결과

[DEBUG] s.m.selectTest  - ==>  Preparing: select * from test_table where value is null 
[DEBUG] s.m.selectTest  - ==> Parameters: 
[DEBUG] s.m.selectTest  - <==      Total: 1
TestTable [id=2, value=null]

[DEBUG] s.m.selectTest  - ==>  Preparing: select * from test_table where value = ? 
[DEBUG] s.m.selectTest  - ==> Parameters: hoge(String)
[DEBUG] s.m.selectTest  - <==      Total: 1
TestTable [id=1, value=hoge]

설명

  • <choose> 태그를 사용하면 여러 옵션 중 하나를 적용하는 조건을 정의할 수 있다.
  • <when> 태그에서 지정한 조건이 충족된 경우 SQL을 작성한다.
  • <otherwise> 태그는 그 이외의 모든 조건이 충족되지 않은 경우 SQL을 작성한다.



where, trim

DB 테이블

test_table

idstringnumber
1hoge100
2hoge200
3fuga200
4piyo400

소스 코드

sample_mapper.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="sample.mybatis">

  <select id="selectTest" resultType="sample.mybatis.TestTable">
    select *
      from test_table
    <where>
      <if test="string != null">
        and string = #{string}
      </if>
      <if test="number != null">
        and number = #{number}
      </if>
    </where>
  </select>
</mapper>

Main.java

package sample.mybatis;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Main {

    public static void main(String[] args) throws Exception {
        try (InputStream in = Main.class.getResourceAsStream("/mybatis-config.xml")) {
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

            try (SqlSession session = factory.openSession()) {
                // 매개 변수를 빈 오브젝트로 실행
                Map<String, Object> param = new HashMap<>();
                selectAndPrint(session, param);

                // 매개 변수를 string만 지정해서 실행
                param = new HashMap<>();
                param.put("string", "hoge");
                selectAndPrint(session, param);

                // 매개 변수를 string과 number를 지정해서 실행
                param = new HashMap<>();
                param.put("string", "hoge");
                param.put("number", 200);
                selectAndPrint(session, param);
            }
        }
    }

    private static void selectAndPrint(SqlSession session, Map<String, Object> param) {
        session
            .selectList("sample.mybatis.selectTest", param)
            .forEach(System.out::println);
        System.out.println();
    }
}

실행 결과

[DEBUG] s.m.selectTest  - ==>  Preparing: select * from test_table 
[DEBUG] s.m.selectTest  - ==> Parameters: 
[DEBUG] s.m.selectTest  - <==      Total: 4
TestTable [id=1, string=hoge, number=100]
TestTable [id=2, string=hoge, number=200]
TestTable [id=3, string=fuga, number=200]
TestTable [id=4, string=piyo, number=300]

[DEBUG] s.m.selectTest  - ==>  Preparing: select * from test_table WHERE string = ? 
[DEBUG] s.m.selectTest  - ==> Parameters: hoge(String)
[DEBUG] s.m.selectTest  - <==      Total: 2
TestTable [id=1, string=hoge, number=100]
TestTable [id=2, string=hoge, number=200]

[DEBUG] s.m.selectTest  - ==>  Preparing: select * from test_table WHERE string = ? and number = ? 
[DEBUG] s.m.selectTest  - ==> Parameters: hoge(String), 200(Integer)
[DEBUG] s.m.selectTest  - <==      Total: 1
TestTable [id=2, string=hoge, number=200]

설명

  • <where> 태그를 사용하면, 자식 요소가 어떤 문자열이 존재하는 경우에만 WHERE 절을 선두에 추가해주게 된다.
  • 또한 <where> 태그 내의 문자열이 AND 또는 OR로 시작하면 자동으로 그 조건 연결문이 제거된다.
  • 이 동작은 <if> 등 만으로 작성하게 되면 상당히 복잡한 작성이 되어 버리지만, 이 <where> 태그를 사용해서 간단히 작성할 수 있다.

trim 태그로 대체

위의 <where>를 사용한 정의는 <trim> 태그를 사용하여 다음과 같이 바꿀 수 있다.

sample_mapper.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="sample.mybatis">

  <select id="selectTest" resultType="sample.mybatis.TestTable">
    select *
      from test_table
    <trim prefix="where" prefixOverrides="AND|OR">
      <if test="string != null">
        and string = #{string}
      </if>
      <if test="number != null">
        and number = #{number}
      </if>
    </trim>
  </select>
</mapper>
  • prefix 속성에 앞에 추가할 문자열를 추가한다.
  • prefixOverrides 속성에 처음부터 제거하는 문자열을 파이프 (|)로 구분한다.


set, trim

DB 테이블

test_table

idstringnumber
1hoge100
2hoge200
3fuga200
4piyo100

소스 코드

TestTable.java

package sample.mybatis;

public class TestTable {
    private int id;
    private String string;
    private Integer number;

    public TestTable id(int id) {
        this.id = id;
        return this;
    }

    public TestTable string(String string) {
        this.string = string;
        return this;
    }

    public TestTable number(int number) {
        this.number = number;
        return this;
    }
}

sample_mapper.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="sample.mybatis">

  <update id="updateTest">
    update test_table
    <set>
      <if test="string != null">
        string = #{string},
      </if>
      <if test="number != null">
        number = #{number},
      </if>
    </set>
    where id = #{id}
  </update>
</mapper>

Main.java

package sample.mybatis;

import java.io.InputStream;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Main {

    public static void main(String[] args) throws Exception {
        try (InputStream in = Main.class.getResourceAsStream("/mybatis-config.xml")) {
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

            try (SqlSession session = factory.openSession()) {
                session.update("sample.mybatis.updateTest",
                        new TestTable().id(1).number(555));

                session.update("sample.mybatis.updateTest",
                        new TestTable().id(3).string("update").number(999));

                session.commit();
            }
        }
    }
}

실행 결과

[DEBUG] s.m.updateTest  - ==>  Preparing: update test_table SET number = ? where id = ? 
[DEBUG] s.m.updateTest  - ==> Parameters: 555(Integer), 1(Integer)
[DEBUG] s.m.updateTest  - <==    Updates: 1
[DEBUG] s.m.updateTest  - ==>  Preparing: update test_table SET string = ?, number = ? where id = ? 
[DEBUG] s.m.updateTest  - ==> Parameters: update(String), 999(Integer), 3(Integer)
[DEBUG] s.m.updateTest  - <==    Updates: 1
test_table

test_table

idstringnumber
1hoge555
2hoge200
3update999
4piyo300

설명

  • <set> 태그를 사용하면 내부 문자열이 비어 있지 않은 경우 앞에 SET 절이 추가된다.
  • 또한 끝에 쉼표 (,)가 자동으로 제거된다.

trim 태그로 대체

<where> 때와 마찬가지로 <trim>로 대체 할 수도 있다.

sample_mapper.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="sample.mybatis">

  <update id="updateTest">
    update test_table
    <trim prefix="set" suffixOverrides=",">
      <if test="string != null">
        string = #{string},
      </if>
      <if test="number != null">
        number = #{number},
      </if>
    </trim>
    where id = #{id}
  </update>
</mapper>
  • suffixOverrides 속성에 마지막에 제거하는 문자을 지정한다.


foreach

bind

소스 코드

sample_mapper.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="sample.mybatis">

  <select id="selectTest" resultType="sample.mybatis.TestTable">
    <bind name="parameter" value="'@@@' + _parameter + '@@@'"/>
    select *
      from test_table
     where value = #{parameter}
  </select>
</mapper>

Main.java

package sample.mybatis;

import java.io.InputStream;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Main {

    public static void main(String[] args) throws Exception {
        try (InputStream in = Main.class.getResourceAsStream("/mybatis-config.xml")) {
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

            try (SqlSession session = factory.openSession()) {
                session.selectList("sample.mybatis.selectTest", "abc");
            }
        }
    }
}

실행 결과

[DEBUG] s.m.selectTest  - ==>  Preparing: select * from test_table where value = ? 
[DEBUG] s.m.selectTest  - ==> Parameters: @@@abc@@@(String)

설명

  • <bind> 태그에서 임시 변수를 정의 할 수 있다.
  • name 속성에 임시 변수의 이름을 정의한다.
  • value 속성에 OGNL(Object Graph Navigation Language) 표현식을 사용한 값의 정의가 있다.
  • _parameter는 매개 변수로 전달된 값을 참조할 암시 변수이다 (특수 매개 변수 이름 참조).



'MyBatis' 카테고리의 다른 글

[MyBatis] Spring Boot와 연계  (0) 2017.12.31
[MyBatis] 프로그램에서 SQL을 동적으로 생성  (0) 2017.12.31
[MyBatis] 동적 SQL  (0) 2017.12.31
[MyBatis] Mapper  (0) 2017.12.31
[MyBatis] 배치(batch) 갱신  (0) 2017.12.31
[MyBatis] 삭제 DELETE  (0) 2017.12.31

지금까지 우리는 SqlSession에 직접 Statement ID 및 매개 변수를 전달하는 방법으로 SQL을 실행을 하였다.

MyBatis는 이와는 별도로 Mapper라는 구조도 준비되어있다. Mapper를 사용하면 SqlSession을 직접 사용하는 형태보다 안전하게 된다.

기본적으로 이 Mapper를 사용하는 방법이 더 좋다. (맵핑 파일이 자동으로 Mapper 단위가 되기 때문에 관리도 쉬워진다)



기본

DB 테이블

test_table

idstringnumber
1hoge100
2fuga200
3piyo300

소스 코드

TestTable.java

package sample.mybatis;

public class TestTable {
    private int id;
    private String string;
    private int number;

    @Override
    public String toString() {
        return "TestTable [id=" + id + ", string=" + string + ", number=" + number + "]";
    }
}

sample_mapper.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="sample.mybatis.TestTableMapper"> <!-- Mapper의 FQCN을 namespace으로 한다. -->

  <select id="selectAll" resultType="sample.mybatis.TestTable">
    select *
      from test_table
  </select>
</mapper>

TestTableMapper.java

package sample.mybatis;

import java.util.List;

// Mapper 인터페이스
public interface TestTableMapper {

    // Statement ID와 같은 이름의 메소드 정의
    List<TestTable> selectAll();
}

Main.java

package sample.mybatis;

import java.io.InputStream;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Main {

    public static void main(String[] args) throws Exception {
        try (InputStream in = Main.class.getResourceAsStream("/mybatis-config.xml")) {
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

            try (SqlSession session = factory.openSession()) {
                // Mapper의 인스턴스를 얻는다.
                TestTableMapper mapper = session.getMapper(TestTableMapper.class);

                mapper.selectAll().forEach(System.out::println);
            }
        }
    }
}

실행 결과

[DEBUG] s.m.T.selectAll - ==>  Preparing: select * from test_table 
[DEBUG] s.m.T.selectAll - ==> Parameters: 
[DEBUG] s.m.T.selectAll - <==      Total: 3
TestTable [id=1, string=hoge, number=100]
TestTable [id=2, string=fuga, number=200]
TestTable [id=3, string=piyo, number=300]

설명

  • Mapper를 사용하는 경우, 전용 인터페이스를 정의한다(TestTableMapper).
    • 이 인터페이스의 메소드와 설정 파일의 각 Statement에 대응되도록 하여 각각을 정의한다.
    • Statement에서는 namespace를 인터페이스의 FQCN한다(sample.mybatis.TestTableMapper).
    • Statement ID와 인터페이스의 메소드 이름과 일치시킨다(selectAll).
    • 매개 변수가 존재하는 경우는 메소드에 인수를 전달하도록 정의한다.
  • Mapper 인스턴스는 SqlSession의 getMapper() 메소드로 취득한다.



매개 변수를 여러 인자에 나누어 전달


'MyBatis' 카테고리의 다른 글

[MyBatis] 프로그램에서 SQL을 동적으로 생성  (0) 2017.12.31
[MyBatis] 동적 SQL  (0) 2017.12.31
[MyBatis] Mapper  (0) 2017.12.31
[MyBatis] 배치(batch) 갱신  (0) 2017.12.31
[MyBatis] 삭제 DELETE  (0) 2017.12.31
[MyBatis] 변경 UPDATE  (0) 2017.12.31

기본적으로 SQL을 실행할 때마다 PreparedStatement를 생성하여 SQL을 데이터베이스에 전송하고 있다.

업데이트 건수가 많은 경우, 이것은 매우 효율이 나쁘다.

MyBatis는 설정에 따라 PreparedStatement의 재사용과 배치 갱신이 가능하게 되어있다.

기본 동작

소스 코드

sample_mapper.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="sample.mybatis">

  <insert id="insertTest">
    insert into test_table (value) values (#{value})
  </insert>
</mapper>

Main.java

package sample.mybatis;

import java.io.InputStream;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Main {

    public static void main(String[] args) throws Exception {
        try (InputStream in = Main.class.getResourceAsStream("/mybatis-config.xml")) {
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

            try (SqlSession session = factory.openSession()) {
                for (int i=0; i<3; i++) {
                    TestTable t = new TestTable("value-" + i);
                    int updateCount = session.insert("sample.mybatis.insertTest", t);
                    System.out.println("updateCount = " + updateCount);
                }

                session.commit();
            }
        }
    }
}
  • 3회 반복하여 INSERT를 실행하도록 구현하였다.

실행 결과

[DEBUG] s.m.insertTest  - ==>  Preparing: insert into test_table (value) values (?) 
[DEBUG] s.m.insertTest  - ==> Parameters: value-0(String)
[DEBUG] s.m.insertTest  - <==    Updates: 1
updateCount = 1
[DEBUG] s.m.insertTest  - ==>  Preparing: insert into test_table (value) values (?) 
[DEBUG] s.m.insertTest  - ==> Parameters: value-1(String)
[DEBUG] s.m.insertTest  - <==    Updates: 1
updateCount = 1
[DEBUG] s.m.insertTest  - ==>  Preparing: insert into test_table (value) values (?) 
[DEBUG] s.m.insertTest  - ==> Parameters: value-2(String)
[DEBUG] s.m.insertTest  - <==    Updates: 1
updateCount = 1

설명

  • 매번 PreparedStatement가 생성되어 SQL이 전송되고 있다.

PreparedStatement을 재이용한다.

소스 코드

mybatis-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>
  <settings>
    <setting name="defaultExecutorType" value="REUSE"/>
  </settings>

  ...
</configuration>

실행 결과

[DEBUG] s.m.insertTest  - ==>  Preparing: insert into test_table (value) values (?) 
[DEBUG] s.m.insertTest  - ==> Parameters: value-0(String)
[DEBUG] s.m.insertTest  - <==    Updates: 1
updateCount = 1
[DEBUG] s.m.insertTest  - ==> Parameters: value-1(String)
[DEBUG] s.m.insertTest  - <==    Updates: 1
updateCount = 1
[DEBUG] s.m.insertTest  - ==> Parameters: value-2(String)
[DEBUG] s.m.insertTest  - <==    Updates: 1
updateCount = 1

설명

  • 설정 파일에서 defaultExecutorType에 REUSE를 설정한다.
  • PreparedStatement가 한번만 생성된다.
  • SQL의 전송은 매번 이루어지고 있다.

배치 실행

소스 코드

mybatis-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>
  <settings>
    <setting name="defaultExecutorType" value="BATCH"/>
  </settings>

  ...
</configuration>

실행 결과

[DEBUG] s.m.insertTest  - ==>  Preparing: insert into test_table (value) values (?) 
[DEBUG] s.m.insertTest  - ==> Parameters: value-0(String)
updateCount = -2147482646
[DEBUG] s.m.insertTest  - ==> Parameters: value-1(String)
updateCount = -2147482646
[DEBUG] s.m.insertTest  - ==> Parameters: value-2(String)
updateCount = -2147482646

설명

  • defaultExecutorType를 BATCH로 하면 일괄 업데이트된다.
  • SQL의 전송은 마지막으로 함께 진행된다.
  • 그래서, 업데이트 건수는 얻을 수 없게 되어있다.

SqlSession을 얻을 때 지정한다.

배치 갱신할지 여부의 설정은 SqlSession을 얻을 때의 인수로 지정할 수있다.

import org.apache.ibatis.session.ExecutorType;

...

SqlSession session = factory.openSession(ExecutorType.BATCH);

openSession()의 인수에 ExecutorType를 전달하여 지정할 수 있다. 여기에 지정된 조건은 설정 파일보다 우선된다.

'MyBatis' 카테고리의 다른 글

[MyBatis] 동적 SQL  (0) 2017.12.31
[MyBatis] Mapper  (0) 2017.12.31
[MyBatis] 배치(batch) 갱신  (0) 2017.12.31
[MyBatis] 삭제 DELETE  (0) 2017.12.31
[MyBatis] 변경 UPDATE  (0) 2017.12.31
[MyBatis] 등록 INSERT  (1) 2017.12.31

+ Recent posts