MyBatis | Mapping Query Results to Arbitrary Java Objects | Delaying the Loading of Related Objects
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="{key1=bar_key1,key2=bar_key2}" select="selectBar"
fetchType="lazy" /> <!-- Set fetchType to lazy. -->
</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>
Foo.java
package sample.mybatis;
public class Foo {
private int id;
public Bar bar;
public void method() {
System.out.println("Foo.method() is called");
}
}
Main.java
package sample.mybatis;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Main {
public static void main(String[] args) throws Exception {
try (InputStream in = Main.class.getResourceAsStream("/mybatis-config.xml")) {
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
try (SqlSession session = factory.openSession()) {
System.out.println("@selectList()");
List<Foo> result = session.selectList("sample.mybatis.selectFoo");
System.out.println("@result.get(0)");
Foo foo = result.get(0);
System.out.println("** foo.class = " + foo.getClass() + " **");
System.out.println("@foo.bar 1");
System.out.println("<< foo.bar = " + foo.bar + " >>");
System.out.println("@foo.method()");
foo.method();
System.out.println("@foo.bar 2");
System.out.println("<< foo.bar = " + foo.bar + " >>");
}
}
}
}
Execution result
@selectList()
[DEBUG] s.m.selectFoo - ==> Preparing: select * from foo_table
[DEBUG] s.m.selectFoo - ==> Parameters:
[DEBUG] s.m.selectFoo - <== Total: 3
@result.get(0)
** foo.class = class sample.mybatis.Foo_$$_jvst80f_0 **
@foo.bar 1
<< foo.bar = null >>
@foo.method()
[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
Foo.method() is called
@foo.bar 2
<< foo.bar = Bar [key1=1, key2=fuga] >>
Explanation
- Setting the fetchType attribute of
<association>to lazy delays loading of the related object.- The default is eager loading.
- An instance of a class configured for lazy loading becomes a proxy generated by MyBatis (class sample.mybatis.Foo _ $$ _ jvst80f_0).
- When lazy loading is not used, a normal instance is passed.
- Lazy loading appears to run when one of the proxy methods is executed.
- Since it does not run when the field is read, the field is null if it is referenced before a method call. In practice, direct field access is not usually something you would expose, but this behavior is worth noting.
Setting lazyLoadingEnabled in the root configuration when you want lazy loading by default
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="lazyLoadingEnabled" value="true"/> <!-- Set it to true. -->
</settings>
...
</configuration>
- Even in this case, the fetchType setting on the
<association>tag takes precedence, so you can override the setting when you want only a specific load to be eager.