MyBatis / Javaのオブジェクトの永続化支援


mybatis」はJavaオブジェクトとSQLを紐付ける永続化のためのフレームワークです。SQLベースで実装できるため実行するSQLに柔軟性があり、実行SQLの見通しもよく、メンテナンスしやすさを保てるのが特徴です。

😎 インストール

build.gradleに次の内容を追加してgradle buildを実行。

buildscript {
repositories {
mavenCentral()
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile 'org.mybatis:mybatis:3.4.4'
compile group: 'postgresql', name: 'postgresql', version: '9.0-801.jdbc4'
compileOnly 'org.projectlombok:lombok:1.16.16'
}

🗻 DBの準備

PostgreSQLのインストール

PostgreSQLのインストールは「macOS SierraへのPostgreSQLインストール」を参照ください。

DBとユーザーの作成

DBとユーザーを作成します。

createuser -s mybatis_test -P
createdb mybatis_test -O mybatis_test

SQLを実行してテストテーブルを作成します。

CREATE TABLE test_table (
id int,
content VARCHAR(255)
)
;
INSERT INTO test_table VALUES (1, 'hoge');
INSERT INTO test_table VALUES (2, 'fuga');
INSERT INTO test_table VALUES (3, 'pugi');

🎉 SQLパラメータ&結果をJavaオブジェクトで取得

以下を実現するコードを紹介します。

  • SQLのパラメータを渡す
  • 受け取った結果をJavaオブジェクトに渡す

フォルダ構成

├── build.gradle
└── src
└── main
├── java
│   └── sample
│   └── mybatis
│   ├── MybatisSample.java
│   ├── TestTable.java
│   └── TestTableMapper.java
└── resources
├── mybatis-config.xml
└── sample_mapper.xml

設定ファイル

DBとの接続情報を記述した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>
<environments default="sample_id">
<environment id="sample_id">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="org.postgresql.Driver"/>
<property name="url" value="jdbc:postgresql://localhost:5432/mybatis_test"/>
<property name="username" value="mybatis_test"/>
<property name="password" value="mybatis_test"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="sample_mapper.xml"/>
</mappers>
</configuration>

sample_mapper.xmlへのSQLの定義は次のように行います。パラメータは#{xxx}で定義します。

<?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">
<select id="findBy" resultType="sample.mybatis.TestTable">
SELECT
*
FROM
test_table
WHERE
id = #{id}
AND content = #{content}
</select>
</mapper>

Mapper

MyBatisのMapperを使うことで直感的で読みやすく、SQLと紐付けを行うことができます。

import java.util.List;
// Mapper インターフェース
public interface TestTableMapper {
// ステートメントID と同じ名前のメソッドを定義する
List<TestTable> findBy(@Param("id") int id, @Param("content") String content);
}

SQLの結果をマッピングするJavaオブジェクト

SQLの結果をマッピングするJavaオブジェクトTestTable.javaを定義します。

public class TestTable {
private int id;
private String content;
public TestTable(int id, String content) {
this.id = id;
this.content = content;
}
public int getId() {
return this.id;
}
public String getContent() {
return this.content;
}
@Override
public String toString() {
return "TestTable [id=" + id + ", content=" + content + "]";
}
}

実行コード

パラメータを渡して、対応するデータを取得するJavaのコードは次のとおりです。

public class MybatisSample {
public static void main(String[] args) throws Exception {
// 設定ファイルを読み込む
try (InputStream in = MybatisSample.class.getResourceAsStream("/mybatis-config.xml")) {
// 設定ファイルからSQL実行のためSqlSessionFactoryを生成
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
// SqlSessionFactory => SqlSessionを生成
try (SqlSession session = factory.openSession()) {
TestTableMapper mapper = session.getMapper(TestTableMapper.class);
mapper.findBy(1, "hoge").forEach(System.out::println);
}
}
}
}

実行結果

TestTable [id=1, values=hoge]

SQLへの引数の受け渡しと実行結果をJavaオブジェクトにセットできていることがわかります。

🏀 ifタグで動的にSQLを変更

SQL内に<if></if>タグでSQLのwhere構文を値を動的に変更できます。

<?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">
<select id="findBy" resultType="sample.mybatis.TestTable">
SELECT
*
FROM
test_table
<where>
<if test="id > 0">
AND id = #{id}
</if>
<if test="values_args != null">
AND values = #{values_args}
</if>
</where>
</select>
</mapper>

🚕 trimタグでUpdate文を変更

SQL内に<trim></trim>タグを使うことでUpdate SQL文を動的に置き換えることができます。

<?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">
<update id="update">
update test_table
<trim prefix="set" suffixOverrides=",">
<if test="content != null">
content = #{content},
</if>
</trim>
where id = #{id}
</update>
</mapper>

🐮 Sequenceを取得してidを設定

DBのSequenceからidを取得してからinsert文を実行する場合はsample_mapper.xmlを次のように設定します。

ample_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="create">
<selectKey keyProperty="id" resultType="_int" order="BEFORE">
select test_table_seq.nextval from dual
</selectKey>
insert into test_table (
id
,value
) values (
#{id}
,#{value}
)
</insert>
</mapper>

🗽 生SQLの実行

@Selectなどのアノテーションを使うとSQLを直接コードに埋めて実行ができます。Testなどでダミーデータを登録するのに便利です。

Mapper側にメソッドを定義します。

public interface TestTableMapper {
@Select("select count(*) from (${sql}) as t")
Long count(@Param("sql") String sql);
}

Mapperの呼び出し側は次のようにSQLを呼び出します。

public class MybatisSample {
public static void main(String[] args) throws Exception {
// 設定ファイルを読み込む
try (InputStream in = MybatisSample.class.getResourceAsStream("/mybatis-config.xml")) {
// 設定ファイルからSQL実行のためSqlSessionFactoryを生成
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
// SqlSessionFactory => SqlSessionを生成
try (SqlSession session = factory.openSession()) {
TestTableMapper mapper = session.getMapper(TestTableMapper.class);
Long count = mapper.countBySql("select * from test_table");
System.out.println(count);
}
}
}

実行結果は次のとおりで、件数を取得できているのがわかります。

3

😼 ResultTypeの設定値

  • プリミティブ型は_intのように_を最初につける
  • 参照型、オリジナルのクラスを設定してbindすることもできる

🐝 MyBatis関連オブジェクトのスコープ

インスタンス 概要 スコープ
SqlSessionFactoryBuilder mybatis-config.xmlの設定ファイルを読み込む メソッド内だけで使い捨て
SqlSessionFactory SqlSessionを生成するメソッド。一度作ったら使いまわす アプリケーション内で使いまわす
SqlSession SQL実行で使う。1連のSQLを実行したらcloseする リクエスト間でだけ使いまわす

🐯 実行されるSQLをログ出力

実行するSQLをログに出力する場合は「Logback Home」をbuild.gradleに追加すればDEBUGレベルで出力できます。

compile 'ch.qos.logback:logback-classic:1.1.3'

ログの出力結果は次のようになります。

07:36:11.111 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [org.postgresql.jdbc4.Jdbc4Connection@5f9d02cb]
07:36:11.114 [main] DEBUG sample.mybatis.selectTest - ==> Preparing: SELECT * FROM test_table WHERE id = ? AND values = ?
07:36:11.186 [main] DEBUG sample.mybatis.selectTest - ==> Parameters: 1(Integer), hoge(String)
07:36:11.283 [main] DEBUG sample.mybatis.selectTest - <== Total: 1
---------------
id=1, values=hoge
07:36:11.381 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [org.postgresql.jdbc4.Jdbc4Connection@5f9d02cb]
07:36:11.382 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Closing JDBC Connection [org.postgresql.jdbc4.Jdbc4Connection@5f9d02cb]
07:36:11.383 [main] DEBUG o.a.i.d.pooled.PooledDataSource - Returned connection 1604125387 to pool.

🍣 スネークケースとキャメルケースの自動マッピング

テーブルのスネークケースとキャメルケースの自動マッピングを行う場合はmybatis-config.xmlに以下を追加します。

<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
...
</configuration>

🐠 キャッシュについて

  • 検索結果はキャッシュされる。(デフォルトでは1024個のオブジェクトをキャッシュ)
  • キャッシュはセッションごとに保持される
  • 使われていないキャッシュから削除される
  • insert, update, deleteが実行されるとキャッシュがクリア

🎃 補足:><はCDATAで囲む

><を使う場合はCDATAで対象のSQLを囲むことで使えます。

<![CDATA[
select
1
from
products
where
price > 500
]]>

😀 Daoでの引数について

Daoファイルでインターフェイスを規定する場合に、引数が復数ある場合は必ず@Param xxxを指定すること。

public List<com.test.myTest> getAllbyDate(@Param("date") Date date, @Param("myid") int myid);

ちなみに、@Paramの指定がない場合のエラーは次のようになります。

org.apache.ibatis.binding.BindingException: Parameter 'myid' not found. Available parameters are [1, 0, param1, param2]

すぐに紐付けられずにハマったことがあるのでくれぐれも注意してください。

🚌 参考リンク

🖥 VULTRおすすめ

VULTR」はVPSサーバのサービスです。日本にリージョンがあり、最安は512MBで2.5ドル/月($0.004/時間)で借りることができます。4GBメモリでも月20ドルです。 最近はVULTRのヘビーユーザーになので、「ここ」から会員登録してもらえるとサービス開発が捗ります!

📚 おすすめの書籍