Unveiling MyBatis: How Mapper Interfaces Bind and SQL Executes Internally

This article dissects MyBatis' internal workflow, explaining how mapper interfaces are bound to XML files, detailing the step‑by‑step SQL execution process, and showing how to create custom typeHandlers for parameter and result mapping, all illustrated with diagrams and code examples.

Java Interview Crash Guide
Java Interview Crash Guide
Java Interview Crash Guide
Unveiling MyBatis: How Mapper Interfaces Bind and SQL Executes Internally

Introduction

MyBatis is widely used, yet many developers are unclear about its SQL execution flow; this article clarifies that process.

How mapper interfaces and XML files are bound

MyBatis SQL execution flow

Custom parameter typeHandler implementation

Custom result set typeHandler implementation

PS: The analysis is based on MyBatis 3.5.5 source code.

Overview

Programmatic data queries in MyBatis typically involve the following code:

SqlSession session = sqlSessionFactory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
List<LwUser> userList = userMapper.listUserByUserName("孤狼1号");

The first line obtains a SqlSession, the second retrieves the UserMapper interface, and the third line executes the entire query.

Getting Mapper Interface (getMapper)

After obtaining a SqlSession, calling getMapper triggers the runtime sequence shown below.

1. getMapper looks up the mapper in the Configuration object, which already holds all mapper interfaces loaded at startup.

2. The MapperRegistry inside Configuration is consulted.

3. Based on the type, the appropriate proxy factory is retrieved from knownMappers and a proxy instance is created.

4. The final MapperProxy object is obtained, which implements InvocationHandler using JDK dynamic proxies.

When Mapper Interface and XML Are Linked

Mapper interfaces and their XML files are stored during the loading of the mybatis-config.xml file, as shown in the following sequence diagram.

1. SqlSessionFactoryBuilder.build() is called.

2. An XMLConfigBuilder is created and its parse method is invoked.

3. The mappers node is parsed, ultimately linking each XML file to its corresponding mapper interface.

4. The parser builds an XMLMapperBuilder for each XML file and calls its parse method.

During parsing, circular dependencies may cause partial failures, but MyBatis will attempt to resolve them later during query execution.

After parsing, bindMapperForNamespace binds the mapper interface to its XML, and Configuration.addMapper registers the mapper in knownMappers.

SQL Execution Flow Analysis

Because the mapper is wrapped by a proxy, invoking a mapper method triggers the proxy’s invoke method, which eventually constructs a MapperMethod containing the SQL statement, parameters, and return type.

The execution consists of two major steps:

Finding the SQL

Executing the SQL

Finding the SQL

The proxy checks whether the method is a default method; otherwise it creates a MapperMethod that encapsulates the mapped statement.

Executing the SQL

The execute method selects the appropriate execution path based on the statement type; for a collection result it calls executeForMany, which eventually invokes PreparedStatementHandler.query and runs the JDBC execute method.

Parameters are set via StatementHandler.parameterize, which delegates to the appropriate TypeHandler (e.g., StringTypeHandler calls PreparedStatement.setString).

Custom TypeHandler

To customize parameter handling, implement BaseTypeHandler and override its four methods. Example:

package com.lonelyWolf.mybatis.typeHandler;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.*;

public class MyTypeHandler extends BaseTypeHandler<String> {
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        System.out.println("Custom typeHandler applied for setting parameter");
        ps.setString(i, parameter);
    }
    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        System.out.println("Custom typeHandler applied for getting result by column name");
        return rs.getString(columnName);
    }
    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        System.out.println("Custom typeHandler applied for getting result by column index");
        return rs.getString(columnIndex);
    }
    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return cs.getString(columnIndex);
    }
}

Use it in a mapper XML:

<resultMap id="MyUserResultMap" type="lwUser">
    <result column="user_id" property="userId" jdbcType="VARCHAR" typeHandler="com.lonelyWolf.mybatis.typeHandler.MyTypeHandler"/>
    <result column="user_name" property="userName" jdbcType="VARCHAR"/>
</resultMap>

<select id="listUserByUserName" parameterType="String" resultMap="MyUserResultMap">
    select user_id, user_name from lw_user where user_name=#{userName,jdbcType=VARCHAR,typeHandler=com.lonelyWolf.mybatis.typeHandler.MyTypeHandler}
</select>

Running the query prints the custom handler messages, confirming it works.

Result Set Mapping

After the SQL is executed, ResultSetHandler.handleResultSets processes the result set using the configured TypeHandler s.

Workflow Diagram

The overall MyBatis workflow involves four core objects under SqlSession (Executor, StatementHandler, ParameterHandler, ResultSetHandler), which are later intercepted for advanced features.

Conclusion

This article dissected MyBatis' SQL execution pipeline, demonstrated how mapper interfaces bind to XML files, and showed how to create custom typeHandler s for both parameter and result mapping. While MyBatis provides sensible defaults for most cases, custom handlers are valuable when special processing is required.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaBackend DevelopmentMyBatisSQL ExecutionTypeHandlerMapper Interface
Java Interview Crash Guide
Written by

Java Interview Crash Guide

Dedicated to sharing Java interview Q&A; follow and reply "java" to receive a free premium Java interview guide.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.