スタートガイド

インストール

MyBatis を使用するには、mybatis-x.x.x.jar ファイルをクラスパスに含めるだけです。

Maven を使用している場合は、次の依存関係を pom.xml に追加してください。

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

XML から SqlSessionFactory を構築する

すべての MyBatis アプリケーションは、SqlSessionFactory のインスタンスを中心に展開されます。SqlSessionFactory のインスタンスは、SqlSessionFactoryBuilder を使用して取得できます。SqlSessionFactoryBuilder は、XML 設定ファイルまたは Configuration クラスのカスタム準備済みインスタンスから SqlSessionFactory インスタンスを構築できます。

XML ファイルから SqlSessionFactory インスタンスを構築するのは非常に簡単です。この構成にはクラスパスリソースを使用することをお勧めしますが、リテラルファイルパスまたは file:// URL から作成されたものを含む、任意の InputStream インスタンスを使用できます。MyBatis には、クラスパスやその他の場所からリソースを簡単にロードできるようにする多くのメソッドを含む、Resources というユーティリティクラスが含まれています。

String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory =
  new SqlSessionFactoryBuilder().build(inputStream);

設定 XML ファイルには、データベース接続インスタンスを取得するための DataSource や、トランザクションのスコープと制御方法を決定するための TransactionManager など、MyBatis システムの中核となる設定が含まれています。XML 設定ファイルの詳細は、このドキュメントで後ほど詳しく説明しますが、簡単な例を次に示します。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.dokyumento.jp//DTD Config 3.0//EN"
  "https://mybatis.dokyumento.jp/dtd/mybatis-3-config.dtd">
<configuration>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

XML 設定ファイルには他にも多くの要素がありますが、上記の例では最も重要な部分を指摘しています。XML ドキュメントを検証するために必要な XML ヘッダーに注目してください。環境要素の本体には、トランザクション管理と接続プーリングの環境構成が含まれています。マッパー要素には、SQL コードとマッピング定義を含むマッパー(XML ファイルおよび/またはアノテーション付き Java インターフェースクラス)のリストが含まれています。

XML なしで SqlSessionFactory を構築する

XML ではなく Java から構成を直接構築する場合や、独自の構成ビルダーを作成する場合は、MyBatis は XML ファイルと同じ構成オプションをすべて提供する完全な Configuration クラスを提供します。

DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory =
  new JdbcTransactionFactory();
Environment environment =
  new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory =
  new SqlSessionFactoryBuilder().build(configuration);

この場合、構成がマッパークラスを追加していることに注意してください。マッパークラスは、XML マッピングの必要性を回避する SQL マッピングアノテーションを含む Java クラスです。ただし、Java アノテーションの制限と一部の MyBatis マッピングの複雑さにより、最も高度なマッピング(ネストされた結合マッピングなど)には XML マッピングが依然として必要です。このため、MyBatis はピア XML ファイルが存在する場合(この場合、BlogMapper.xml は BlogMapper.class のクラスパスと名前に基づいてロードされます)、自動的に検索してロードします。これについては後で詳しく説明します。

SqlSessionFactory から SqlSession を取得する

SqlSessionFactory があるので、名前が示すように、SqlSession のインスタンスを取得できます。SqlSession には、データベースに対して SQL コマンドを実行するために必要なすべてのメソッドが含まれています。マッピングされた SQL ステートメントを SqlSession インスタンスに対して直接実行できます。たとえば、

try (SqlSession session = sqlSessionFactory.openSession()) {
  Blog blog = session.selectOne(
    "org.mybatis.example.BlogMapper.selectBlog", 101);
}

このアプローチは機能し、以前のバージョンの MyBatis のユーザーには馴染みがありますが、よりクリーンなアプローチが登場しました。ステートメントのパラメーターと戻り値を適切に記述するインターフェース(例:BlogMapper.class)を使用することで、エラーが発生しやすい文字列リテラルやキャストを使用せずに、よりクリーンでタイプセーフなコードを実行できるようになりました。

たとえば、

try (SqlSession session = sqlSessionFactory.openSession()) {
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  Blog blog = mapper.selectBlog(101);
}

次に、ここで正確に何が実行されているかを探りましょう。

マッピングされた SQL ステートメントを調査する

この時点で、SqlSession またはマッパークラスによって正確に何が実行されているか疑問に思うかもしれません。マッピングされた SQL ステートメントのトピックは大きなものであり、このトピックがこのドキュメントの大部分を占める可能性があります。ただし、実行されているものを正確に把握するために、いくつか例を挙げます。

上記のいずれの例でも、ステートメントは XML またはアノテーションのいずれかで定義できます。まず、XML を見てみましょう。MyBatis が長年にわたって人気を博してきた XML ベースのマッピング言語を使用することで、MyBatis が提供する機能のすべてを実現できます。以前に MyBatis を使用したことがある場合は、その概念に慣れていると思いますが、XML マッピングドキュメントには多くの改善が加えられており、後で明確になります。上記の SqlSession 呼び出しを満たす XML ベースのマッピングされたステートメントの例を次に示します。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.dokyumento.jp//DTD Mapper 3.0//EN"
  "https://mybatis.dokyumento.jp/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mybatis.example.BlogMapper">
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  </select>
</mapper>

この簡単な例では、多くのオーバーヘッドがあるように見えますが、実際には非常に軽量です。単一のマッパー XML ファイルで必要な数のマッピングされたステートメントを定義できるため、XML ヘッダーと doctype 宣言を最大限に活用できます。ファイルの残りの部分はかなり自明です。マッピングされたステートメントに「selectBlog」という名前を、名前空間「org.mybatis.example.BlogMapper」で定義します。これにより、上記の例で説明したように、「org.mybatis.example.BlogMapper.selectBlog」の完全修飾名を指定して呼び出すことができます。

Blog blog = session.selectOne(
  "org.mybatis.example.BlogMapper.selectBlog", 101);

これが完全修飾された Java クラスでメソッドを呼び出すのと非常に似ていることに注目してください。それには理由があります。この名前は、名前空間と同じ名前のマッパークラスに直接マッピングでき、マッピングされた select ステートメントと同じ名前、パラメーター、および戻り値の型を持つメソッドがあります。これにより、上記の例で見たように、マッパーインターフェースに対してメソッドを非常に簡単に呼び出すことができます。もう一度次の例を示します。

BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);

2 番目のアプローチには多くの利点があります。まず、文字列リテラルに依存しないため、はるかに安全です。次に、IDE にコード補完機能がある場合は、マッピングされた SQL ステートメントをナビゲートする際に利用できます。


名前空間に関する注意事項。

以前のバージョンの MyBatis では、名前空間はオプションでしたが、これは混乱を招き、役に立ちませんでした。名前空間は必須になり、単に長い完全修飾名でステートメントを分離する以上の目的があります。

名前空間を使用すると、ここで見るようにインターフェースバインディングが可能になります。また、今日使用しないと思っても、気が変わった場合に備えて、ここに示されているプラクティスに従う必要があります。名前空間を 1 回使用し、適切な Java パッケージ名前空間に配置すると、コードが整理され、MyBatis の長期的な使いやすさが向上します。

名前解決: 入力数を減らすために、MyBatis はステートメント、結果マップ、キャッシュなどを含む、名前付きのすべての構成要素に対して、次の名前解決ルールを使用します。

  • 完全修飾名(例:「com.mypackage.MyMapper.selectAllThings」)は直接検索され、見つかった場合は使用されます。
  • 短縮名(例:「selectAllThings」)を使用して、あいまいさのないエントリを参照できます。ただし、2 つ以上(例:「com.foo.selectAllThings」と「com.bar.selectAllThings」)がある場合は、短縮名があいまいであるため、完全修飾する必要があるというエラーが表示されます。

BlogMapper のようなマッパークラスには、もう 1 つのトリックがあります。それらのマッピングされたステートメントは、XML でまったくマッピングする必要はありません。代わりに、Java アノテーションを使用できます。たとえば、上記の XML は削除して、次のように置き換えることができます。

package org.mybatis.example;
public interface BlogMapper {
  @Select("SELECT * FROM blog WHERE id = #{id}")
  Blog selectBlog(int id);
}

アノテーションは単純なステートメントの場合ははるかにクリーンですが、Java アノテーションはより複雑なステートメントの場合は制限があり、煩雑になります。したがって、複雑なことを行う必要がある場合は、XML でマッピングされたステートメントを使用する方が適切です。

どちらが自分にとって適切か、マッピングされたステートメントを一貫した方法で定義することがどれほど重要かは、自分自身とプロジェクトチームで決定することになります。とはいえ、単一のアプローチに縛られることはありません。アノテーションベースのマッピングされたステートメントを XML に、またはその逆に非常に簡単に移行できます。

スコープとライフサイクル

これまで説明してきたさまざまなスコープとライフサイクルクラスを理解することが非常に重要です。それらを誤って使用すると、深刻な同時実行の問題が発生する可能性があります。


オブジェクトのライフサイクルと依存性注入フレームワーク

依存性注入フレームワークは、スレッドセーフなトランザクション SqlSession とマッパーを作成し、それらを直接 Bean に注入できるため、ライフサイクルを忘れてしまう可能性があります。DI フレームワークで MyBatis を使用する方法の詳細については、MyBatis-Spring または MyBatis-Guice サブプロジェクトを参照してください。


SqlSessionFactoryBuilder

このクラスは、インスタンス化、使用、破棄できます。SqlSessionFactory を作成したら、保持する必要はありません。したがって、SqlSessionFactoryBuilder のインスタンスの最適なスコープは、メソッドスコープ(つまり、ローカルメソッド変数)です。SqlSessionFactoryBuilder を再利用して複数の SqlSessionFactory インスタンスを構築できますが、すべての XML 解析リソースがより重要なものに解放されるように、保持しないのが最善です。

SqlSessionFactory

作成された SqlSessionFactory は、アプリケーションの実行中に存在する必要があります。それを破棄したり、再作成したりする理由はほとんどありません。アプリケーションの実行中に SqlSessionFactory を複数回再構築しないのが最良のプラクティスです。そうすることは「悪い匂い」と見なされるべきです。したがって、SqlSessionFactory の最適なスコープは、アプリケーションスコープです。これは、いくつかの方法で実現できます。最も簡単なのは、Singleton パターンまたは Static Singleton パターンを使用することです。

SqlSession

各スレッドには、SqlSession の独自のインスタンスが必要です。SqlSession のインスタンスは共有されず、スレッドセーフではありません。したがって、最適なスコープは、リクエストスコープまたはメソッドスコープです。SqlSession インスタンスへの参照を静的フィールドやクラスのインスタンスフィールドに保持しないでください。SqlSession への参照を、Servlet フレームワークの HttpSession など、管理対象のスコープに保持しないでください。Web フレームワークを使用している場合は、SqlSession が HTTP リクエストと同様のスコープに従うことを検討してください。言い換えれば、HTTP リクエストを受信したら、SqlSession を開き、レスポンスを返したら閉じることができます。セッションを閉じることは非常に重要です。常に finally ブロック内で閉じるようにする必要があります。以下は、SqlSession が閉じられることを保証するための標準的なパターンです。

try (SqlSession session = sqlSessionFactory.openSession()) {
  // do work
}

コード全体でこのパターンを一貫して使用すると、すべてのデータベースリソースが適切に閉じられるようになります。

マッパーインスタンス

マッパーとは、マッピングされたステートメントにバインドするために作成するインターフェースです。マッパーインターフェースのインスタンスは、SqlSessionから取得されます。したがって、技術的には、任意のマッパーインスタンスの最も広いスコープは、それらが要求されたSqlSessionと同じです。ただし、マッパーインスタンスにとって最適なスコープはメソッドスコープです。つまり、それらが使用されるメソッド内で要求し、その後破棄する必要があります。明示的に閉じる必要はありません。SqlSessionと同様に、リクエスト全体を通してそれらを保持しておくことは問題ありませんが、このレベルで多すぎるリソースを管理すると、すぐに手に負えなくなる可能性があります。シンプルに保ち、マッパーはメソッドスコープに保持してください。次の例でこのプラクティスを示します。

try (SqlSession session = sqlSessionFactory.openSession()) {
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  // do work
}