MyBatis マッピング

最終更新: 2025-10-21 15:55:03 +0800 +0800
tags: Java | Mybatis | Sql
原文は英語で書かれています。あなたはAI翻訳版を読んでいます。

MyBatis は Java 呼び出しを SQL 文にマッピングし、パラメータのバインディング、 文の実行、結果セットへのアクセスは JDBC が担います。マッパーはこの境界を 明確にする必要があります。SQL の列名は文に記述し、Java のプロパティ名は パラメータおよび結果マッピングに記述し、標準とは異なる変換は型ハンドラーで 実行します。

パラメータと結果の境界 #

単純なパラメータには #{id} プレースホルダーを使用できます。オブジェクトおよび マップのパラメータは名前付きプロパティを公開します。複数のマッパーパラメータには @Param を使用し、名前がコンパイラーのメタデータに依存しないようにします。

java
List<Task> findByState(@Param("state") State state,
                       @Param("limit") int limit);

#{...} は JDBC パラメータマーカーを作成し、値をバインドします。${...} は 準備前に SQL へテキストを代入するため、パラメータ化できない、許可リストで管理された 識別子またはフラグメントに限定して使用します。リクエストデータを ${...} 式に 直接配置してはいけません。

列ラベルと Java プロパティが一致する場合、自動結果マッピングは簡潔です。名前が 異なる場合、ネストされたオブジェクトに明示的な識別性が必要な場合、または結合に よって親行が重複する可能性がある場合は、resultMap を使用します。

xml
<resultMap id="taskResult" type="com.example.Task">
  <id property="id" column="task_id"/>
  <result property="name" column="task_name"/>
  <result property="state" column="state"
          typeHandler="com.example.StateTypeHandler"/>
</resultMap>

<id> マッピングは結合結果内のオブジェクトを識別し、重複した親データを MyBatis が まとめるのに役立ちます。これはデータベース制約を宣言するものではありません。 スキーマ側で引き続き識別性を保証する必要があります。

生成キー #

生成キーをサポートするデータベースおよび JDBC ドライバーでは、 useGeneratedKeys を有効にし、書き込み可能な Java プロパティを指定します。 MyBatis は INSERT 後に JDBC の生成キー API を呼び出し、生成された主キーをその プロパティに割り当てます。

xml
<insert id="insert"
        parameterType="com.example.Task"
        useGeneratedKeys="true"
        keyProperty="id">
  INSERT INTO task (name) VALUES (#{name})
</insert>
java
Task task = new Task();
task.setName("import");
mapper.insert(task);
long id = task.getId();

割り当てられるのは生成キーのプロパティだけです。データベースのデフォルト値、 トリガーで生成される列、その他のフィールドは再読み込みされません。追加の SELECT、サポートされている場合はデータベースの RETURNING 句、または データベースがシーケンスを使用する場合やドライバーが getGeneratedKeys を サポートしない場合は selectKey 文を使用します。

NULL パラメータ #

xml
UPDATE task
SET completed_at = #{completedAt, jdbcType=TIMESTAMP}
WHERE id = #{id}

グローバルな jdbcTypeForNull は、すべての NULL 許容パラメータに対して データベースの規約が適合する場合にのみ設定します。SQL 型が異なる列では、 パラメータごとに型を指定する方が明確です。生成キーおよび NULL バインディングの 動作はドライバー固有であるため、本番環境のドライバーに対して INSERT と UPDATE をテストします。

動的 SQL と型ハンドラー #

動的要素は、任意のアプリケーションテキストを連結せずに文の構造を構築します。

xml
<select id="find" resultMap="taskResult">
  SELECT id AS task_id, name AS task_name, state
  FROM task
  <where>
    <if test="state != null">
      state = #{state, typeHandler=com.example.StateTypeHandler}
    </if>
  </where>
  ORDER BY id
</select>

<where> は子要素が条件を出力する場合にのみ WHERE を挿入し、先頭の AND または OR を削除します。関連する要素には <choose>、<set>、<trim>、 <foreach> があります。TypeHandler は、列挙型を安定した文字列として保存する 場合のように、意図的な Java/JDBC 表現を定義する必要があります。同じ Java 型を 異なる列が異なる方法でエンコードする場合は、対象を限定して登録します。

セッションとトランザクションの所有権 #

マッピングされた文は SqlSession を介して実行されます。MyBatis を直接使用する 場合、呼び出し側がセッションを開き、コミットまたはロールバックを実行し、閉じます。

java
try (SqlSession session = factory.openSession()) {
    TaskMapper mapper = session.getMapper(TaskMapper.class);
    mapper.insert(task);
    session.commit();
}

デフォルトのセッションは autocommit ではなく、SqlSession はスレッドセーフでは ありません。MyBatis-Spring などのフレームワーク統合では、セッションがフレーム ワーク管理のトランザクションにバインドされます。アプリケーションコードでは、 この所有権モデルに対して手動コミットを混在させてはいけません。生成キーの割り当ては 文の実行中に行われますが、所有側のトランザクションがコミットされるまで行は永続化 されません。

参考資料 #

コメント

GitHub で閲覧・コメントする(投稿にはログインが必要です)