Mybatis
Li Wei
MyBatis
Overview
ORM (Object Relational Mapping) refers to the pattern that maps persistent data to entity objects, solving the mismatch between object‑oriented programming and relational databases.
MyBatis
- MyBatis is an excellent Java‑based persistence framework that wraps JDBC, allowing developers to focus on the SQL statements themselves without dealing with driver loading, connection creation, or
Statementhandling. - It configures the statements to be executed via XML or annotations and maps Java objects to the dynamic parameters in those statements, generating the final SQL to run.
- The framework executes the SQL, maps the results to Java objects, and returns them. By adopting ORM concepts, it solves the entity‑to‑database mapping problem, encapsulates JDBC, and hides the low‑level API details, so we can perform persistence operations without directly using the JDBC API.
Official MyBatis website:
Basic Operations
Relevant APIs
Resources – utility class for loading resources
InputStream getResourceAsStream(String fileName): Returns an input stream for the specified resource using the class loader.- The
fileNameparameter is the core configuration file placed insrc: MyBatisConfig.xml
SqlSessionFactoryBuilder – builder used to obtain a SqlSessionFactory
SqlSessionFactory build(InputStream is): Obtains aSqlSessionFactoryfrom a given resource’s input stream.
SqlSessionFactory – factory interface for obtaining SqlSession builders
SqlSession openSession(): Gets aSqlSessionbuilder and opens a session with manual commit.SqlSession openSession(boolean): Gets aSqlSessionbuilder withtrueto enable auto‑commit.
SqlSession – the session object used to execute SQL, manage transactions, and create mapper proxies
- A
SqlSessionrepresents a single interaction with the database and must be closed after use. - Like
Connection,SqlSessionis not thread‑safe; obtain a new instance for each use.
Note: Updates must be committed, either manually or by enabling auto‑commit.
Common SqlSession API
| Method | Description |
|---|---|
List<T> selectList(String statement, Object parameter) |
Executes a query and returns a List of results |
T selectOne(String statement, Object parameter) |
Executes a query and returns a single result object |
int insert(String statement, Object parameter) |
Executes an insert and returns the number of rows affected |
int update(String statement, Object parameter) |
Executes an update and returns the number of rows affected |
int delete(String statement, Object parameter) |
Executes a delete and returns the number of rows affected |
void commit() |
Commits the transaction |
void rollback() |
Rolls back the transaction |
T getMapper(Class<T> cls) |
Retrieves the proxy implementation of the specified mapper interface |
void close() |
Releases resources |
Mapper Configuration
Mapper XML files define the mapping between data and objects as well as the SQL statements to execute. They reside under the src directory.
File name: StudentMapper.xml
Header:
- Root tag:
<mapper>– the core root element namespaceattribute: the namespace (usually the fully‑qualified mapper interface name)
- Root tag:
CRUD tags:
<select>– query operation<insert>– insert operation<update>– update operation<delete>– delete operation
Common attributes:
id: unique identifier, used together with the namespaceresultType: fully‑qualified class name of the result object (must match the method’s return type; if the return type is aList, it must match the generic type)parameterType: fully‑qualified class name of the parameter object (must match the method’s parameter type)statementType(optional):STATEMENT,PREPARED, orCALLABLE. Default isPREPARED.STATEMENT: Direct SQL execution usingStatement(no pre‑compilation). Parameter placeholder:$PREPARED: Pre‑processed parameters usingPreparedStatement. Placeholder:#CALLABLE: Executes stored procedures viaCallableStatement
Parameter binding syntax:
- SQL parameter placeholder:
#{属性名}
- SQL parameter placeholder:
Recommended official documentation: https://mybatis.org/mybatis-3/zh/sqlmap-xml.html
Core Configuration
The core configuration file holds the most important MyBatis settings, such as database connection, transaction handling, and connection‑pool information.
File name: MyBatisConfig.xml
Header:
- Root tag:
<configuration>– the core root element
- Root tag:
Include external files:
<properties>– includes external property files (e.g., database connection settings)resourceattribute: specifies the file name
Settings:
<settings>– can modify runtime behavior (e.g., enable cache, lazy loading)
Type aliases:
<typeAliases>– parent tag for defining aliases for fully‑qualified class names<typeAlias>– child tag that maps an alias to a classtype: fully‑qualified class namealias: desired alias
<package>– automatically creates aliases for all classes in a package; the alias is the class name with the first letter lower‑cased
Built‑in aliases:
Alias Java type stringjava.lang.Stringlongjava.lang.Longintjava.lang.Integerdoublejava.lang.Doublebooleanjava.lang.Boolean… … Environments: You can define multiple
<environment>tags.<environments default="dev">– selects which environment is active<environment id="dev">– unique identifier matching thedefaultattribute<transactionManager type="JDBC">– transaction manager (default is JDBC)<dataSource type="POOLED">– data source;POOLEDuses MyBatis’s built‑in connection pool,UNPOOLEDdisables pooling- Child tags (
<property>) specifydriver,url,username,passwordand their values.
- Child tags (
Mapper registration:
<mappers>– parent tag for mapper inclusion<mapper resource="StudentMapper.xml"/>– include by resource name<mapper url="..."/>– include via URL (network or file system)<mapper class="com.example.mapper.StudentMapper"/>– include by fully‑qualified class name<mapper>can also be used for batch registration.
#{} vs ${}
#{}– placeholder. The supplied value is treated as a string and automatically quoted. It is passed to the database via a prepared statement (?), which prevents SQL injection and improves security.${}– literal substitution. The value is inserted directly into the SQL without quoting, which can lead to injection vulnerabilities.
Use
#{}wherever possible; avoid or minimize${}.
When ${} is required:
- When a table name is a parameter, e.g.,
SELECT * FROM ${tableName} - In
ORDER BYclauses, e.g.,SELECT * FROM t_user ORDER BY ${columnName}
Note: Use #{} for SQL parameters and ${} for values read from properties files.
Logging
During development, you often need to see the exact SQL MyBatis executes, along with parameters and results. This can be achieved with Log4j.
- Add the Log4j dependency in
pom.xml. - Configure Log4j inside the root
<configuration>tag of the core config file. - Create a
log4j.propertiesfile undersrc.
Code Example
- Entity class
StudentMapperinterfaceconfig.propertiesMyBatisConfig.xmlStudentMapper.xml- Controller test code: query by ID
- Controller test code: insert operation
Batch Operations
Three ways to perform batch operations:
Global batch (via
<settings>attribute):defaultExecutorTypesets the default executor type.SIMPLE– ordinary executor (default; parameters are set each time)REUSE– reuses prepared statements (parameters set once, executed multiple times)BATCH– reuses statements and performs batch updates (only for modification operations)
Session‑level batch using
SqlSession.Spring configuration (
applicationContext.xml) for batch execution.
Mapper‑Based Development
Proxy Rules
Layered architecture: controller → service → DAO.
Traditional DAO requires an interface and an implementation class. With MyBatis’s mapper proxy approach, you only write the mapper interface (equivalent to a DAO interface); MyBatis generates a dynamic proxy for it at runtime.
Interface‑first development:
- Define the mapper interface.
- MyBatis creates a proxy that handles all database interactions.
Mapper interface conventions:
- The
namespaceinMapper.xmlmust match the fully‑qualified name of the mapper interface. - The
idattribute of CRUD tags inMapper.xmlmust match the method names in the mapper interface. - The
parameterTypeattribute must match the method’s parameter type. - The
resultTypeattribute must match the method’s return type.
How It Works
MyBatis uses JDK dynamic proxies. When you call sqlSession.getMapper(YourMapper.class), you receive a MapperProxy instance. Method invocations on this proxy are delegated to MapperMethod.execute(), which determines the operation type (insert, update, delete, select) via a switch statement and finally delegates to the underlying SqlSession to run the SQL.
Result Mapping
Relevant Tags
<resultMap>– defines the result object type; must align with the method’s return type (or generic type if returning aList).<result>– maps a single column to a property; used to configure field‑to‑property mapping (alternative toresultType).idattribute: unique identifiertypeattribute: the Java class of the result objectautoMappingattribute: enables automatic mapping
Core configuration tags for result mapping:
<id>– maps primary‑key columns<result>– maps non‑primary‑key columnscolumn: column name in the tableproperty: corresponding Java field name
<association>– maps a single nested object (one‑to‑one or many‑to‑one).property: name of the nested object field in the parent classjavaType: Java type of the nested objectselect: ID of a separateselectstatement used to load the nested object; the column specified bycolumnis passed as a parameter
<collection>– maps a collection of nested objects (one‑to‑many or many‑to‑many).property: name of the collection field in the parent classofType: Java type of the elements in the collection
<discriminator>– determines which mapping to use based on the value of a particular column, allowing custom object construction based on that value.
Nested Queries
A nested query can be used for complex object graphs. Circular references are resolved through caching.
Multi‑Table Queries
One‑to‑One
Steps:
- Prepare bean classes.
- Create
OneToOneMapper.xmland include it inMyBatisConfig.xml(you can alias the bean package). - Configure
MyBatisConfig.xml. - Write a test class.
One‑to‑Many
Steps:
- Prepare bean classes.
- Create the mapper XML.
- Implement the necessary code snippets.
Many‑to‑Many
Example: student‑course relationship where the join table does not need a separate bean class.
- Prepare bean classes.
- Create the mapper XML.
Discriminator Example
Requirement: If the query result indicates a female, fetch department information; otherwise, do not. If male, populate the last_name column.
Loading Strategies
Eager vs. Lazy Loading
Eager loading: The query runs immediately when the method is called.
Lazy loading: Data is fetched only when accessed. MyBatis supports lazy loading for one‑to‑one and one‑to‑many associations.
- Pros: Reduces unnecessary joins; improves performance for queries that often need only the main table.
- Cons: May increase total query time when many lazy‑loaded objects are eventually accessed, potentially hurting user experience.
Core configuration options:
| Tag/Attribute | Description | Default |
|---|---|---|
lazyLoadingEnabled |
Global switch for lazy loading. When true, all associations are lazy unless overridden with fetchType. |
false |
aggressiveLazyLoading |
When true, any method call loads all lazy properties of the object; otherwise, each lazy property loads on demand. | false |
Lazy loading is implemented using CGLIB dynamic proxies:
- CGLIB creates a proxy for the target mapper that has lazy loading enabled.
- When a lazy property’s getter is invoked, the proxy’s interceptor detects a
nullvalue, triggers the SQL query, sets the property, and returns the value.
association
Step‑by‑step query: first retrieve the owner’s ID, then use that ID to fetch the full owner information.
In
OneToOneMapper.xml(one‑to‑one mapping):columnattribute supplies the parameter for the referencedselecttag.selectattribute names the otherselectstatement to invoke.fetchType="lazy"enables lazy loading for this association only.
Example files:
PersonMapper.xml,PersonMapper.java, and a test class.
collection
In a one‑to‑many mapping, the collection node also supports lazy loading with select and column attributes.
In
OneToManyMapper.xml(one‑to‑many mapping):columnspecifies which column’s value is used as the condition for the nested query.selectpoints to the mapper method that retrieves the collection items (full qualified DAO class name + method name).
Example file:
StudentMapper.xml.
Annotation‑Based Development
Single‑Table Operations
Annotations can replace XML mapper files, simplifying development.
Common annotations:
@Select("SQL query")– query operation@Insert("SQL insert")– insert operation@Update("SQL update")– update operation@Delete("SQL delete")– delete operation
Parameter annotation:
@Param– used when a SQL statement requires multiple (>1) parameters to map method arguments to named placeholders.
Core configuration: Map the mapper interfaces to MyBatis via <mapper class="..."/> in MyBatisConfig.xml.
Typical steps:
- Create the mapper interface with annotated methods.
- Adjust the core configuration file to scan the mapper package.
- Define the bean class.
- Write test code.
Multi‑Table Operations
Relevant Annotations
When moving from XML to annotations for complex relationships, you can use:
@Results(replaces<resultMap>)@Result(replaces<result>and<id>)@One(for one‑to‑one associations)@Many(for one‑to‑many collections)
@Results example:
@Results({
@Result(column = "id", property = "id", id = true),
@Result(column = "name", property = "name"),
@Result(column = "dept_id", property = "department",
one = @One(select = "com.example.mapper.DepartmentMapper.selectById"))
})
These annotations allow you to configure complex object graphs directly on the mapper interface without separate XML files.
Originally written by Li Wei (李唯_) and published in Chinese on 后端技术栈全书 (Full-Stack Backend Engineering). Translated and adapted for DriftSeas with permission.