MyBatis Advanced Mapping and Lazy Loading Techniques

Database Schema Overview

Before implementing the code examples, it's essential to understand the database table structure that we'll be working with.

Many-to-One Relationships

For our examples, we'll consider a PostContent table (primary key) as the "many" side and a Post table as the "one" side.

Appproach 1: Cascade Property Mapping

First, create the entity classes with appropriate relationships:

package com.example.mybatis.advanced.pojo;

public class PostContent {
    private Integer id;
    private String content;
    private Post post; // Many-to-one relationship - add Post reference in the "many" side
    
    // Constructors, getters, setters, and toString() method
}

Next, configure the mapping file:

<?xml version="1.0" encoding="UTF-8" ??>
<mapper namespace="com.example.mybatis.advanced.mapper.PostContentMapper">
    <resultmap id="PostContentResultMap" type="PostContent">
        <id column="id" property="id"></id>
        <result column="content" property="content"></result>
        <result column="postId" property="post.id"></result>
        <result column="user_id" property="post.userId"></result>
        <result column="title" property="post.title"></result>
        <result column="summary" property="post.summary"></result>
        <result column="view_count" property="post.viewCount"></result>
        <result column="publish_time" property="post.publishTime"></result>
        <result column="update_time" property="post.updateTime"></result>
    </resultmap>
    
    <select id="selectPostContentById" resultmap="PostContentResultMap">
        SELECT
            c.*, p.id postId, p.user_id, p.title, p.summary, p.view_count, p.publish_time, p.update_time
        FROM
            post_content c LEFT JOIN post p ON c.post_id = p.id
        WHERE
            c.id = #{id}
    </select>
</mapper>

Implement the test case:

@Test
public void testSelectPostContentById() {
    SqlSession sqlSession = SqlSessionUtil.openSqlSession();
    PostContentMapper mapper = sqlSession.getMapper(PostContentMapper.class);
    PostContent postContent = mapper.selectPostContentById(1);
    
    System.out.println(postContent);
    System.out.println(postContent.getPost());
    
    sqlSession.close();
}

Approach 2: Association Mapping

Modify only the resultMap configuration to use the association tag:

<resultmap id="PostContentResultMap" type="PostContent">
    <id column="id" property="id"></id>
    <result column="content" property="content"></result>
    <association javatype="Post" property="post">
        <id column="postId" property="id"></id>
        <result column="user_id" property="userId"></result>
        <result column="title" property="title"></result>
        <result column="summary" property="summary"></result>
        <result column="view_count" property="viewCount"></result>
        <result column="publish_time" property="publishTime"></result>
        <result column="update_time" property="updateTime"></result>
    </association>
</resultmap>

Approach 3: Step-by-Step Querying

Implement this approach in three steps:

Step 1: Add a method to the PostMapper interface:

package com.example.mybatis.advanced.mapper;

import com.example.mybatis.advanced.pojo.Post;

public interface PostMapper {
    Post selectPostById(Integer id);
}

Step 2: Configure the PostMapper.xml file:

<?xml version="1.0" encoding="UTF-8" ??>
<mapper namespace="com.example.mybatis.advanced.mapper.PostMapper">
    <select id="selectPostById" resulttype="Post">
        SELECT * FROM post WHERE id = #{id};
    </select>
</mapper>

Step 3: Update the PostContentMapper.xml file to use association with select attribute:

<?xml version="1.0" encoding="UTF-8" ??>
<mapper namespace="com.example.mybatis.advanced.mapper.PostContentMapper">
    <resultmap id="PostContentResultMap" type="PostContent">
        <id column="id" property="id"></id>
        <result column="content" property="content"></result>
        <association column="post_id" property="post" select="com.example.mybatis.advanced.mapper.PostMapper.selectPostById"></association>
    </resultmap>
    
    <select id="selectPostContentById" resultmap="PostContentResultMap">
        SELECT * FROM post_content WHERE id = #{id};
    </select>
</mapper>

One-to-Many Relationships

For one-to-many relationships, we typically add a List collection property to the "one" side entity:

package com.example.mybatis.advanced.pojo;

import java.util.Date;
import java.util.List;

public class Post {
    private Integer id;
    private Integer userId;
    private String title;
    private String summary;
    private Integer viewCount;
    private Date publishTime;
    private Date updateTime;
    private List<postcontent> contents;
    
    // Constructors, getters, setters, and toString() method
}</postcontent>

Approach 1: Collection Mapping

Add a method to PostMapper interface:

public interface PostMapper {
    Post selectPostById(Integer id);
}

Create the PostMapper.xml mapping file:

<?xml version="1.0" encoding="UTF-8" ??>
<mapper namespace="com.example.mybatis.advanced.mapper.PostMapper">
    <resultmap id="PostResultMap" type="Post">
        <id column="id" property="id"></id>
        <result column="user_id" property="userId"></result>
        <result column="title" property="title"></result>
        <result column="summary" property="summary"></result>
        <result column="view_count" property="viewCount"></result>
        <result column="publish_time" property="publishTime"></result>
        <result column="update_time" property="updateTime"></result>
        <collection oftype="PostContent" property="contents">
            <id column="contentId" property="id"></id>
            <result column="content" property="content"></result>
        </collection>
    </resultmap>
    
    <select id="selectPostById" resultmap="PostResultMap">
        SELECT
            p.*, c.id contentId, c.content
        FROM
            post p LEFT JOIN post_content c ON p.id = c.post_id
        WHERE p.id = #{id}
    </select>
</mapper>

Implement the test program:

@Test
public void testSelectPostById() {
    SqlSession sqlSession = SqlSessionUtil.openSqlSession();
    PostMapper mapper = sqlSession.getMapper(PostMapper.class);
    Post post = mapper.selectPostById(1);
    
    System.out.println(post);
    System.out.println(post.getContents());
    
    sqlSession.close();
}

Approach 2: Step-by-Step Querying

Similar to the many-to-one approach, modify three components:

Step 1: Update the mapping file:

<?xml version="1.0" encoding="UTF-8" ??>
<mapper namespace="com.example.mybatis.advanced.mapper.PostMapper">
    <resultmap id="PostResultMap" type="Post">
        <id column="id" property="id"></id>
        <result column="user_id" property="userId"></result>
        <result column="title" property="title"></result>
        <result column="summary" property="summary"></result>
        <result column="view_count" property="viewCount"></result>
        <result column="publish_time" property="publishTime"></result>
        <result column="update_time" property="updateTime"></result>
        <collection column="id" property="contents" select="com.example.mybatis.advanced.mapper.PostContentMapper.selectContentsByPostId"></collection>
    </resultmap>
    
    <select id="selectPostById" resultmap="PostResultMap">
        SELECT * FROM post WHERE id = #{id};
    </select>
</mapper>

Step 2: Add a method to PostContentMapper interface:

/**
 * Retrieves all content for a specific post ID
 * @param postId The ID of the post
 * @return List of content items for the specified post
 */
List<postcontent> selectContentsByPostId(Integer postId);
</postcontent>

Step 3: Configure the SQL statement in PostContentMapper.xml:

<select id="selectContentsByPostId" resulttype="PostContent">
    SELECT * FROM post_content WHERE post_id = #{postId};
</select>

Lazy Loading

Benefits of Step-by-Step Querying

  1. Enhanced Reusability: Breaking down complex queries into smaller, reusable components.
  2. Lazy Loading Support: Enables efficient data loading only when needed.

Understanding Lazy Loading

Lazy loading operates on the principle of executing queries only when data is actually needed, not during initial loading. This approach optimizes performance by minimizing unnecessary database queries.

Implementing Lazy Loading in MyBatis

To enable lazy loading for specific associations:

<association column="post_id" fetchtype="lazy" property="post" select="com.example.mybatis.advanced.mapper.PostMapper.selectPostById"></association>

Note: By default, lazy loading is disabled. You must explicitly set fetchType="lazy" for the specific association.

Global Lazy Loading Configuration

In most applications, you'll want lazy loading enabled globally. Configure this in the MyBatis core configuration file:

<settings>
    <setting name="lazyLoadingEnabled" value="true"></setting>
</settings>

Recommended Development Pattern

  1. Enable global lazy loading in the configuration.
  2. For associations that require immediate loading, set fetchType="eager".

Tags: MyBatis ORM Database Mapping Lazy Loading data persistence

Posted on Thu, 29 Oct 2026 16:20:03 +0000 by jonemo