Jakarta EE 10 で MyBatis を使ってみる

Red Hat で Java 関連を担当している伊藤ちひろです。

本記事は、Jakarta EE 10と一緒に MyBatis を使う方法を紹介します。 MyBatis 自体の使い方は説明しません。 Jakarta EE 10で MyBatis を使う方法に焦点をあてます。

MyBatis は Java SE や Jakarta EE の仕様と連携できます。 本記事では以下の構成で MyBatis を使ってみます。

  • MyBatis を Contexts and Dependency Injection (CDI) で使えるようにする
  • トランザクション管理は Jakarta Transactions
  • コネクション管理はAPサーバから javax.sql.DataSource を提供

サンプルは JBoss EAP 8.0 で動作を確認しています。 サンプルはこちら

プロジェクトの設定

MyBatis を CDI と組み合わせて使うには、mybatismybatis-cdiという2つの依存を追加します。 これらはどちらもorg.mybatisというグループIDです。 アプリケーションのpom.xmlに以下のように追記します。

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-cdi</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.16</version>
        </dependency>

設定ファイル

次に、MyBatisの設定ファイルです。 ここでは、以下を設定します。

  • トランザクションのライフサイクル管理をアプリケーションサーバに任せる(transactionManager要素)
  • データソースをアプリケーションサーバに定義済みのものを使う (dataSource要素)

アプリケーションサーバで、data_sourceプロパティに設定してあるデータソースを作成する必要があります。

また、あとのステップで設定が正しく行われたかどうかを確認するため、ログを出力するように設定しています。

src/main/resources/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="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <environments default="Postgres">
        <environment id="Postgres">
            <transactionManager type="MANAGED"/>
            <dataSource type="JNDI">
                <property name="data_source" value="java:jboss/datasources/PostgreSQLDS"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!-- マッパーファイルの一覧を記述 -->
    </mappers>
</configuration>

ファクトリ

最後に、MyBatis のクライアントを CDI で使えるようにするため、CDI の Producerを作成します。 この Producer は org.apache.ibatis.session.SqlSessionFactory を作成します。 複数のデータベースにアクセスする場合は、Producer に限定子(Qualifier) を設定することで、SqlSessionFactory を使い分けられるようにします。

以下は、Producer のサンプルコードです。 上述の設定ファイルを使用しています。

package org.example;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.Dependent;
import jakarta.enterprise.inject.Produces;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.mybatis.cdi.SessionFactoryProvider;

import java.io.IOException;
import java.io.InputStream;

@Dependent
public class SqlSessionFactoryProducer {

    @Produces
    @ApplicationScoped
    @SessionFactoryProvider
    public SqlSessionFactory produceFactory() throws IOException {
        InputStream fileStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(fileStream);
        return sqlSessionFactory;
    }
}

動作確認

Producer で SqlSessionFactory を作成できたかどうか確認します。 アプリケーションをデプロイすると以下のようなログが出力されれば成功です。 もし、先頭の 2 行だけが出力され、最後の Managed SqlSession: の行が出力されていない場合は失敗です。

21:22:11,832 INFO  [org.mybatis.cdi.MybatisExtension] (MSC service thread 1-8) MyBatis CDI Module - SqlSessionFactory producer SqlSessionFactoryProducer.produceFactory
21:22:11,851 INFO  [org.mybatis.cdi.MybatisExtension] (MSC service thread 1-8) MyBatis CDI Module - Activated
21:22:11,851 INFO  [org.mybatis.cdi.MybatisExtension] (MSC service thread 1-8) MyBatis CDI Module - Managed SqlSession: org.apache.ibatis.session.SqlSession, org.apache.ibatis.session.SqlSession

MyBatisを使う

ログがきちんと出力されるようになったら、org.apache.ibatis.session.SqlSession のオブジェクトを DI できます。 これは、CDI で普通に @Inject を付けて DI します。

package org.example;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

@Path("/hello")
public class HelloResource {

    @Inject
    SqlSession sqlSession;

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<SampleEntity> hello() {
        return sqlSession.selectList("findList");
    }
}

参考:Java EE + iBATIS から Jakarta EE + MyBatis への移行

MyBatis の前身である iBATIS は、未だに Java EE と一緒によく使われています。 iBATIS から MyBatis へ移行する場合は、以下が必要です。

  • 使用するクラスとメソッドの変更
  • マッパーファイルの変更

使用するクラスはcom.ibatis.sqlmap.client.SqlMapClient から org.apache.ibatis.session.SqlSession に変わります。 メソッドも変わるため、Javadocを見ながら適切なものへ変更していきましょう。

既存のマッパーファイルが多い場合には手作業で変換するのは大変です。 そのため、変換ツールが公式から公開されています。 また、公式以外でも変換ツールを公開されている方もいらっしゃいました。

私が使った感想としては、マッパーファイルが古すぎるとどちらも変換できませんでした。 これは、マッパーファイルのDOCTYPE要素に記載されているDTDのホスト名が異なるためでした。 この問題に遭遇した場合はホスト名の部分を ibatis.apache.org に変更してから変更してください。

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。