【Spring Boot】【Mybatis】Xmlベースで結合SQLによるマッピング実装

【Spring Boot】【Mybatis】Xmlベースで結合SQLによるマッピング実装

前回の続きです。
前提などは1回目の記事を確認してください。

Xmlベースで結合SQLによるマッピング実装

前回はSQLを3つ使用してネストされたオブジェクトへのマッピングを実装していましたが、Xmlの場合であればFrom句を複数指定した結合SQLでのマッピングも可能です。
※アノテーションベースではできません。

コード

DemoMapperXml.java

package com.example.demo.repository;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import com.example.demo.entity.Country;

@Mapper
public interface DemoMapperXml {

    Country selectCountry(@Param("id") Integer id);

}

アノテーションベースに比べるとすっきりしています。

DemoMapperXml.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="com.example.demo.repository.DemoMapperXml">
    
    <resultMap id="countryMap" type="com.example.demo.entity.Country" >
    
        <!-- <result column="country_id" property="countryId" /> -->
        <result column="country" property="country" />
        <result column="last_update" property="lastUpdate" />
        
        <association property="id" >
            <result column="country_id" property="countryId" />
        </association>
        
        <collection property="city" ofType="com.example.demo.entity.City">
            <result column="city_id" property="cityId" />
            <result column="city" property="city" />
            <result column="last_update" property="lastUpdate" />
            
            <collection property="address" ofType="com.example.demo.entity.Address">
                <result column="address_id" property="addressId" />
                <result column="address" property="address" />
                <result column="address2" property="address2" />
                <result column="district" property="district" />
                <result column="postal_code" property="postalCode" />
                <result column="phone" property="phone" />
                <result column="last_update" property="lastUpdate" />
            
            </collection>
             
        </collection>
    
    </resultMap>
    <select
        id="selectCountry"
        resultMap="countryMap">
        SELECT *
        FROM
            country,
            city,
            address
        WHERE
            country.country_id = #{id}
        AND
            country.country_id = city.country_id
        AND
            city.city_id = address.city_id
    </select>
</mapper>

説明

まず、SQL文が変わっています。
前回までのSQLではそれぞれのテーブルに対して主キーなどから対応するレコードを取得していましたが、
今回はそれぞれのSQLの条件を一気に指定しています。

後は結果を格納するだけです。
collectionでネストしているオブジェクトを指定し、さらにネストしている場合はcollectionを追加で指定しているという入れ子の構造になっています。

結果

他のマッピング実装と同じくオブジェクトがマッピングできています。

まとめ

ここまでで3つの実装方法を説明してきましたが、前回までの二つの実装

  • DemoMapperがアノテーションベースのマッピング実装
  • DemoMapperXmlがXmlベースで結合SQLによるマッピング実装

については注意が必要です。
なぜならネストした階層ごとにSQLを発行する必要があるため、
ManyからManyのネストなどに対しては大量にSQLを発行してしまい性能面で影響が出る可能性があるためです。
N+1問題とも言われています。
なので、可能であれば複合キーを使って必要なカラムを取得し、Xmlベースでマッピングをしたほうがいいかもしれません。

参考

N+1問題

mybatisカテゴリの最新記事