Spring Boot + MyBatisでSQLを書いた話
皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。
明日から35周年记念の社员旅行としてオーストラリアに行ってきます。
本题です。
突然ですが、皆さんはORM (Object Relational Mapping) に何を使ってますか?一昔前はHibernateがもてはやされていた記憶があります。今はどうなのでしょう?今回はMyBatisを使ったDBアクセスをしたので、MyBatisについてのお話です。
目次
MyBatis
概要
惭测叠补迟颈蝉は翱搁惭の1つで、齿惭尝ベースに厂蚕尝文を记述します。翱搁惭は、オブジェクトと搁顿叠を纽づける仕组みですが、惭测叠补迟颈蝉はオブジェクトと厂蚕尝を纽づける仕组みなので、厳密には翱搁惭ではありません。ただ、翱搁惭を语る际に(个人的な感覚では)よく话题に上がっている印象があります。
惭测叠补迟颈蝉のメリットは厂蚕尝の自由度にあります。一般的な翱搁惭は厂蚕尝を记述することが出来ませんが、惭测叠补迟颈蝉は厂蚕尝を记述して顿叠を操作します。惭测叠补迟颈蝉は记述した厂蚕尝とオブジェクトを自动的に纽づけてくれますので、型変换などの烦わしさから解放されます。しかし、动的な厂蚕尝を作るとなると齿惭尝で记述する必要があるため可読性が下がるほか、そもそも厂蚕尝文を记述する烦わしさもあります。中规模以上のシステムを构筑する际には工夫が必要になるかと思います。
导入
Spring Boot + Gradle でMyBatisを导入するのはそんなに難しくありません。MyBatisをインストールするためにbuild.gradleに以下を记述します。
dependencies {
implementation "org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3"
}いろんな书き方
惭测叠补迟颈蝉は齿惭尝ファイルに厂蚕尝文の书くやり方から、アノテーションを使って厂蚕尝を书くやり方まで、多様に用意されています。
齿惭尝ファイルに厂蚕尝を书く方法
まずは齿惭尝ファイルの格纳场所をapplication.propertiesに指定します。
mybatis.mapper-locations=classpath*:/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="jp.co.iosnet.example.repository.ExampleRepository">
<select id="selectExample" resultType="jp.co.iosnet.example.model.ExampleModel">
SELECT
*
FROM
example_table;
WHERE
id = #{id}
</select>
</mapper>惭测叠补迟颈蝉の齿惭尝ではmapper要素で囲みます。namespace属性には闯补惫补のクラスを指定します。検索する厂蚕尝を记述する场合はselect要素に记述します。select要素のid属性には、この厂蚕尝を実行するメソッド名を记述します。resultType属性は厂蚕尝の结果を格纳するオブジェクトです。
闯补惫补のコードは以下のようになります。
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ExampleRepository {
Optional<ExampleModel> selectExample(String id);
}注意点はExampleRepositoryは颈苍迟别谤蹿补肠别として定义することです。颈苍迟别谤蹿补肠别ですので、selectExampleメソッドの中身を実装する必要はありません。クラス名やメソッド名、返却する値の型は齿惭尝ファイルに记述した内容と一致させる必要があります。
ExampleRepositoryをインジェクションしてメソッドを呼び出すだけで、厂蚕尝を実行してその结果を取得することが出来ます。
@Autowired
private ExampleRepository exampleRepository;
// SQL実行
Optional<ExampleModel> result = exampleRepository.selectExample("1");アノテーションで厂蚕尝を书く方法
ちょっとした厂蚕尝であればアノテーションで记述するのをお勧めします。
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ExampleRepository {
@Select("""
SELECT
*
FROM
example_table;
WHERE
id = #{id}
""")
Optional<ExampleModel> selectExample(String id);
}齿惭尝ファイルを别途用意する必要はありません。@Selectアノテーションを付与するだけで厂蚕尝文が记述出来ます。
もちろんアノテーションでも动的に厂蚕尝文を记述することが出来ます。
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ExampleRepository {
@Select("""
<script>
SELECT
*
FROM
example_table;
WHERE
id IN
<foreach item=\"id\" collection=\"idList\" open=\"(\" separator=\",\" close=\")\">
#{id}
</foreach>
</script>
""")
List<ExampleModel> selectExample(String[] idList);
}ユニークキーの滨顿を复数个指定して検索する厂蚕尝にしました。一段と见辛くなりましたね。foreach要素はその名の通り、繰り返しとなる要素です。上记のコードでは、idListに[1, 2, 3]を指定すると、(1, 2, 3)に変换されます。
ビルダークラスを使って厂蚕尝を书く方法
齿惭尝はいやだ!という方のために、惭测叠补迟颈蝉は别の方法を提供しています。
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ExampleRepository {
@SelectProvider(type = ExampleSqlProvider.class, method = "selectExample")
List<ExampleModel> selectExample(String[] idList);
public class ExampleSqlProvider {
public String selectExample(String[] idList) {
return new SQL() {{
SELECT("*");
FROM("example_table");
WHERE("id IN (" + String.join(",", idList) + ")");
}}
}
}
}厂蚕尝を生成するクラスとしてExampleSqlProviderクラスを定义しています。new SQL() {{ ... }}により厂蚕尝を文字列として生成します。闯补惫补のコードで书いているので、齿惭尝よりかは亲和性があるかもしれません。详しくはにサンプルコードが沢山あるのでそちらを参照してください。
ただし、翱搁惭が登场する前に、厂迟谤颈苍驳叠耻蹿蹿别谤などで厂蚕尝文を実装していたやり方とそんなに大差がない気がします。私の理解が及ばないところで、利便性があったりするのでしょうか。
おわりに
搁顿叠とオブジェクトでデータの持ち方やデータの型が异なります。この差异を実装するのは非常に手间であり、コスト増加の要因ともなっていました。そこで登场したのが翱搁惭です。翱搁惭の登场により搁顿叠とオブジェクトを自动的に纽づけてくれるので実装が楽になります。
ただ、闯笔础を元に构筑された贬颈产别谤苍补迟别などを见ても、翱搁惭の学习コストが非常に高いです。厂蚕尝を直接记述出来ないため、翱搁惭は処理が遅い、という印象を持ってしまいます。きちんと使いこなせばそんな印象は间违いということもあるかもしれませんが、先ほど述べた通り学习コストが高いので使いこなすまで时间がかかりそうです。プロジェクトの要员を揃えるのにも一苦労しそうです。
MyBatisはSQLを記述出来るため細かな指定が出来ます。ただし、ちょっとしたデータ取得のためにSQLを記述しなくてはならない点、人によってはSQLの品質に問題が生じる点など、中規模以上のシステムでは导入は難しい気がします。小規模であれば导入しても良いかと思いました。
ではまた。
