MyBatis core configuration

Published 2026-07-30 19:27 Updated 2026-07-30 19:27 1037 words 6 min read ... Page views

This article introduces the core architecture and configuration of MyBatis, including the use of core configuration files, Mapper interface and XML, SqlSessionFactory and SqlSession, and emphasizes the specifications of environment configuration, property file separation, SQL mapping and result processing. At the same time, it points out the reasons and solutions for common problems such as mapping statements cannot be found, results are null, or write operations are invalid to ensure that various components of MyBatis are correctly configured and used during development.

MyBatis core configuration

The core components of MyBatis

MyBatis projects typically include the following parts:

  • Core configuration files: Configure the runtime environment, data sources, transaction manager and Mapper.
  • Mapper interface: Declare database operation methods.
  • Mapper XML: Write SQL and establish mappings between methods, parameters, and return results.
  • SqlSessionFactory: Create SqlSession based on configuration.
  • SqlSession: Executes SQL, obtains Mapper agents, and manages transactions.

core configuration file

The core configuration file is often named mybatis-config.xml. The file name can be customized, but the actual file name must be used when reading the configuration.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/book_shop"/>
                <property name="username" value="root"/>
                <property name="password" value="1234"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="mapping/BookMapper.xml"/>
    </mappers>
</configuration>

environments can be configured with multiple operating environments, and the value of default must be consistent with the id of a certain environment. The above example selects a mysql environment.

MyBatis not only reads the core configuration file itself, but also loads external property files, Mapper XML and other resources based on the configuration therein. For example, <mapper resource="..."/> means loading the specified mapping file from the classpath, rather than writing the mapping file content directly into the core configuration file.

Using external properties files

Database connection information is usually placed in db.properties to avoid writing directly in XML.

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/book_shop
jdbc.username=root
jdbc.password=1234

Introduce and use these attributes in the core configuration file:

<configuration>
    <properties resource="db.properties"/>

    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

mapper interface

The Mapper interface is used to declare database operations. MyBatis creates proxy objects for interfaces at runtime, so handwritten implementation classes are usually not required.

public interface BookMapper {
    List<TbBook> queryAllBook();

    TbBook queryById(Integer id);

    int insertBook(TbBook book);
}

The method name, parameter type, and return type should be consistent with the configuration of the corresponding statement in Mapper XML.

Mapper XML

Mapper XML is responsible for defining SQL and result mappings.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.oracle.dao.BookMapper">
    <select id="queryAllBook" resultType="com.oracle.entity.TbBook">
        SELECT *
        FROM tb_book
    </select>

    <select id="queryById"
            parameterType="java.lang.Integer"
            resultType="com.oracle.entity.TbBook">
        SELECT *
        FROM tb_book
        WHERE id = #{id}
    </select>

    <insert id="insertBook" parameterType="com.oracle.entity.TbBook">
        INSERT INTO tb_book(book_name, author, price)
        VALUES (#{bookName}, #{author}, #{price})
    </insert>
</mapper>

namespace and id

namespace should fill in the fully qualified class name of the Mapper interface, and id should be consistent with the interface method name. Only when BookMapper.queryAllBook() is called can MyBatis locate the corresponding SQL statement.

parameter placeholders

#{} uses pre-compiled parameters to correctly handle types and reduce the risk of SQL injection. #{} should be used first for general business parameters.

${} is a direct concatenation of strings and is usually only used in locations where parameter placeholders cannot be used, such as sorting fields that have undergone strict whitelist verification. Do not put user input directly into ${}.

MyBatis core API

Create SqlSessionFactory

SqlSessionFactoryBuilder creates SqlSessionFactory based on configuration. Factory objects are costly to create, and only one is usually created in applications.

public final class MyBatisUtil {
    private static final SqlSessionFactory SQL_SESSION_FACTORY;

    static {
        try (InputStream inputStream =
                     Resources.getResourceAsStream("mybatis-config.xml")) {
            SQL_SESSION_FACTORY =
                    new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    private MyBatisUtil() {
    }

    public static SqlSession openSession() {
        return SQL_SESSION_FACTORY.openSession();
    }
}

Using SqlSession

SqlSession is not a thread-safe object and should be created during a business operation and closed in time. After a write operation is performed, the transaction needs to be committed; an exception should be rolled back.

public class BookService {
    public List<TbBook> queryAllBook() {
        try (SqlSession sqlSession = MyBatisUtil.openSession()) {
            BookMapper mapper = sqlSession.getMapper(BookMapper.class);
            return mapper.queryAllBook();
        }
    }

    public int insertBook(TbBook book) {
        try (SqlSession sqlSession = MyBatisUtil.openSession()) {
            BookMapper mapper = sqlSession.getMapper(BookMapper.class);
            try {
                int rows = mapper.insertBook(book);
                sqlSession.commit();
                return rows;
            } catch (RuntimeException e) {
                sqlSession.rollback();
                throw e;
            }
        }
    }
}

You can also use openSession(true) to turn on automatic commit, but manual commit should be used in businesses that require multiple SQL’s to remain atomic.

result mapping

automatic mapping

When the column name of the query result is consistent with the Java attribute name, resultType can be used directly.

<select id="queryById" resultType="com.oracle.entity.TbBook">
    SELECT id, book_name AS bookName, author, price
    FROM tb_book
    WHERE id = #{id}
</select>

If the underscore to hump configuration is enabled, book_name can be automatically mapped to bookName.

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

manual mapping

resultMap should be used when database column names differ significantly from Java attribute names, or complex mappings are required.

<mapper namespace="com.oracle.dao.UserMapper">
    <resultMap id="userMapping" type="com.oracle.entity.User">
        <id property="userId" column="user_id"/>
        <result property="userName" column="user_name"/>
        <result property="realName" column="real_name"/>
        <result property="password" column="password"/>
        <result property="phone" column="phone"/>
        <result property="remain" column="remain"/>
        <result property="operator" column="operator"/>
        <result property="createTime" column="create_time"/>
    </resultMap>

    <select id="queryUserById" resultMap="userMapping">
        SELECT *
        FROM tb_user
        WHERE user_id = #{id}
    </select>
</mapper>

Both resultType and resultMap are used to describe returned results, but only one of them is usually selected for the same query. Use resultType for simple mapping, and use resultMap when you need to clearly specify the correspondence between columns and attributes.

common problems

Unable to find mapping statement

When Invalid bound statement appears, check in turn:

  • Whether Mapper XML is located in the correct resource directory.
  • Whether the core configuration loads the Mapper.
  • Whether namespace is the fully qualified class name of the interface.
  • Whether the id on the SQL label is consistent with the interface method name.
  • Maven builds whether the XML file is copied to the classpath.

The query result attribute is null

Check whether the database column name, Java attribute name and resultMap are consistent; when using hump naming, also check whether mapUnderscoreToCamelCase is turned on.

The write operation did not take effect

By default, SqlSession will not be automatically submitted. After adding, modifying or deleting, commit() should be called; when an exception occurs, rollback() should be called, and finally the session should be closed.

If you enjoyed this, leave a comment~

... Page views
© 2026 跨越星轨的客 @Hoshiumi
Powered by theme astro-koharu · Inspired by Shoka