MyBatis | Mapping Query Results to Arbitrary Java Objects | Splitting SELECT Execution

Splitting SELECT execution for single object mapping

Source code

sample_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="sample.mybatis">

  <resultMap type="sample.mybatis.Foo" id="fooResultMap">
    <id property="id" column="id" />
    <association property="bar" column="bar_id" select="selectBar" />
  </resultMap>

  <select id="selectFoo" resultMap="fooResultMap">
    select * from foo_table
  </select>

  <select id="selectBar" resultType="sample.mybatis.Bar">
    select * from bar_table where id = #{id}
  </select>
</mapper>

Execution result of selectFoo

[DEBUG] s.m.selectFoo   - ==>  Preparing: select * from foo_table 
[DEBUG] s.m.selectFoo   - ==> Parameters: 
[DEBUG] s.m.selectBar   - ====>  Preparing: select * from bar_table where id = ? 
[DEBUG] s.m.selectBar   - ====> Parameters: 1(Integer)
[DEBUG] s.m.selectBar   - <====      Total: 1
[DEBUG] s.m.selectBar   - ====>  Preparing: select * from bar_table where id = ? 
[DEBUG] s.m.selectBar   - ====> Parameters: 2(Integer)
[DEBUG] s.m.selectBar   - <====      Total: 1
[DEBUG] s.m.selectBar   - ====>  Preparing: select * from bar_table where id = ? 
[DEBUG] s.m.selectBar   - ====> Parameters: 3(Integer)
[DEBUG] s.m.selectBar   - <====      Total: 1
[DEBUG] s.m.selectFoo   - <==      Total: 3
Foo [id=3, bar=Bar [id=1]]
Foo [id=2, bar=Bar [id=2]]
Foo [id=1, bar=Bar [id=3]]

Explanation

  • After querying foo_table, MyBatis performs a separate bar_table query for each row.
  • You can perform this kind of query by specifying the statement ID of a <select> tag in the select attribute of the <association> tag.
  • In the column attribute, specify the column used to JOIN the child table.

When there are multiple JOIN keys

DB tables

foo_table

id bar_key1 bar_key2
1 2 hoge
2 1 fuga
3 1 hoge

bar_table

key1 key2
1 fuga
1 hoge
2 hoge

Source code

Bar.java

package sample.mybatis;

public class Bar {
    private int key1;
    private String key2;

    @Override
    public String toString() {
        return "Bar [key1=" + key1 + ", key2=" + key2 + "]";
    }
}

sample_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="sample.mybatis">

  <resultMap type="sample.mybatis.Foo" id="fooResultMap">
    <id property="id" column="id" />
                                <!-- How to specify multiple keys -->
    <association property="bar" column="{key1=bar_key1,key2=bar_key2}" select="selectBar" />
  </resultMap>

  <select id="selectFoo" resultMap="fooResultMap">
    select * from foo_table
  </select>

  <select id="selectBar" resultType="sample.mybatis.Bar">
    select *
      from bar_table
     where key1 = #{key1}
       and key2 = #{key2}
  </select>
</mapper>

Execution result of selectFoo

[DEBUG] s.m.selectFoo   - ==>  Preparing: select * from foo_table 
[DEBUG] s.m.selectFoo   - ==> Parameters: 
[DEBUG] s.m.selectBar   - ====>  Preparing: select * from bar_table where key1 = ? and key2 = ? 
[DEBUG] s.m.selectBar   - ====> Parameters: 1(Integer), fuga(String)
[DEBUG] s.m.selectBar   - <====      Total: 1
[DEBUG] s.m.selectBar   - ====>  Preparing: select * from bar_table where key1 = ? and key2 = ? 
[DEBUG] s.m.selectBar   - ====> Parameters: 1(Integer), hoge(String)
[DEBUG] s.m.selectBar   - <====      Total: 1
[DEBUG] s.m.selectBar   - ====>  Preparing: select * from bar_table where key1 = ? and key2 = ? 
[DEBUG] s.m.selectBar   - ====> Parameters: 2(Integer), hoge(String)
[DEBUG] s.m.selectBar   - <====      Total: 1
[DEBUG] s.m.selectFoo   - <==      Total: 3
Foo [id=2, bar=Bar [key1=1, key2=fuga]]
Foo [id=3, bar=Bar [key1=1, key2=hoge]]
Foo [id=1, bar=Bar [key1=2, key2=hoge]]

Explanation

  • When multiple columns are used for a JOIN, specify the column attribute in the form {prop1=column1, prop2=column2}.

Splitting SELECT execution for collection mapping

Source code

sample_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="sample.mybatis">

  <resultMap type="sample.mybatis.Foo" id="fooResultMap">
    <id property="id" column="id" />
    <collection property="barList" column="id" select="selectBar" />
  </resultMap>

  <select id="selectFoo" resultMap="fooResultMap">
    select * from foo_table
  </select>

  <select id="selectBar" resultType="sample.mybatis.Bar">
    select * from bar_table where foo_id = #{id}
  </select>
</mapper>

Execution result of selectFoo

[DEBUG] s.m.selectFoo   - ==>  Preparing: select * from foo_table 
[DEBUG] s.m.selectFoo   - ==> Parameters: 
[DEBUG] s.m.selectBar   - ====>  Preparing: select * from bar_table where foo_id = ? 
[DEBUG] s.m.selectBar   - ====> Parameters: 1(Integer)
[DEBUG] s.m.selectBar   - <====      Total: 3
[DEBUG] s.m.selectBar   - ====>  Preparing: select * from bar_table where foo_id = ? 
[DEBUG] s.m.selectBar   - ====> Parameters: 2(Integer)
[DEBUG] s.m.selectBar   - <====      Total: 2
[DEBUG] s.m.selectBar   - ====>  Preparing: select * from bar_table where foo_id = ? 
[DEBUG] s.m.selectBar   - ====> Parameters: 3(Integer)
[DEBUG] s.m.selectBar   - <====      Total: 1
[DEBUG] s.m.selectFoo   - <==      Total: 3
Foo [id=1, barList=[Bar [id=1], Bar [id=2], Bar [id=3]]]
Foo [id=2, barList=[Bar [id=4], Bar [id=5]]]
Foo [id=3, barList=[Bar [id=6]]]

Explanation

  • Configure it in the same way as <association>.
  • Lazy loading is also possible.