MyBatis 详细教程
一、MyBatis 概述
MyBatis 是一款优秀的持久层框架,支持定制化 SQL、存储过程以及高级映射。它避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的工作,可以使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJO 映射成数据库中的记录。
作为半自动的 ORM 框架,MyBatis 让开发者将主要精力放在 SQL 上,通过灵活的映射方式自由生成满足需要的 SQL 语句。相较于 Hibernate 和 JPA 这类全自动框架,MyBatis 的 SQL 和 Java 编码分离,功能边界清晰——Java 代码专注业务,SQL 语句专注数据。
二、核心配置文件(mybatis-config.xml)详解
MyBatis 的核心配置文件通常命名为 mybatis-config.xml,是 MyBatis 的启动文件,负责整体引导。该文件以标准 XML 格式开头,根元素为 <configuration>。
2.1 配置文件的基本结构
<?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>
<!-- 属性配置 -->
<properties resource="jdbc.properties" />
<!-- 全局设置 -->
<settings>
...
</settings>
<!-- 类型别名 -->
<typeAliases>
...
</typeAliases>
<!-- 环境配置 -->
<environments default="development">
...
</environments>
<!-- 映射器配置 -->
<mappers>
...
</mappers>
</configuration>核心配置文件中的标签必须按照固定顺序排列:
properties?, settings?, typeAliases?, typeHandlers?,
objectFactory?, objectWrapperFactory?, reflectorFactory?,
plugins?, environments?, databaseIdProvider?, mappers?2.2 properties 属性配置
<properties> 元素用于引入外部属性文件,最常用的方式是引入数据库连接配置文件。
方式一:引入外部 properties 文件
<properties resource="jdbc.properties" />其中 jdbc.properties 文件内容如下:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_example
jdbc.username=root
jdbc.password=123456方式二:直接配置属性
<properties>
<property name="jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbc.url" value="jdbc:mysql://localhost:3306/mybatis_example"/>
<property name="jdbc.username" value="root"/>
<property name="jdbc.password" value="123456"/>
</properties>在后续配置中通过 ${key} 方式引用:
<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>2.3 settings 全局设置
<settings> 元素用于配置 MyBatis 的全局行为,以下是常用的设置项:
<settings>
<!-- 全局开启或关闭所有映射器中已配置的二级缓存 -->
<setting name="cacheEnabled" value="true"/>
<!-- 延迟加载的全局开关,当开启时所有关联对象都会延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 当启用时,任何方法的调用都会加载该对象的所有属性 -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 允许 JDBC 自动生成主键 -->
<setting name="useGeneratedKeys" value="true"/>
<!-- 是否开启自动驼峰命名规则映射 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 配置默认的执行器:SIMPLE/REUSE/BATCH -->
<setting name="defaultExecutorType" value="SIMPLE"/>
<!-- 设置超时时间,它决定驱动等待数据库响应的秒数 -->
<setting name="defaultStatementTimeout" value="25"/>
<!-- 指定 MyBatis 所用日志的具体实现 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>其中 mapUnderscoreToCamelCase 非常实用,开启后数据库字段 user_name 会自动映射到实体类的 userName 属性。lazyLoadingEnabled 开启延迟加载后,关联对象会在真正被使用时才加载,特定关联关系可通过 fetchType 属性覆盖该开关状态。
2.4 typeAliases 类型别名
类型别名可以为 Java 类型设置一个简短的名字,简化映射文件中的配置。
方式一:单个别名定义
<typeAliases>
<typeAlias alias="User" type="com.example.model.User"/>
<typeAlias alias="Order" type="com.example.model.Order"/>
</typeAliases>方式二:包扫描定义别名
<typeAliases>
<package name="com.example.model"/>
</typeAliases>通过 <package> 元素,MyBatis 会扫描指定包下的所有类,将它们的简单类名(首字母小写)作为别名。
2.5 environments 环境配置
<environments> 元素用于配置多个数据库环境,default 属性指定默认使用的环境。一个 environment 代表一个数据库环境,包含事务管理器和数据源配置。
<environments default="development">
<!-- 开发环境 -->
<environment id="development">
<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>
<!-- 生产环境 -->
<environment id="production">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.prod.url}"/>
<property name="username" value="${jdbc.prod.username}"/>
<property name="password" value="${jdbc.prod.password}"/>
</dataSource>
</environment>
</environments>事务管理器类型(transactionManager):
- JDBC:直接使用 JDBC 的提交和回滚设置
- MANAGED:让容器来管理事务的整个生命周期
数据源类型(dataSource):
- UNPOOLED:不使用连接池,每次请求都打开和关闭连接
- POOLED:使用连接池,复用连接对象
- JNDI:使用容器提供的 JNDI 数据源
2.6 mappers 映射器配置
<mappers> 元素用于配置 Mapper 映射文件的位置,有四种配置方式:
<mappers>
<!-- 方式一:使用相对于类路径的资源引用 -->
<mapper resource="mapper/UserMapper.xml"/>
<!-- 方式二:使用完全限定资源定位符(URL) -->
<mapper url="file:///var/mappers/UserMapper.xml"/>
<!-- 方式三:使用映射器接口实现类的完全限定类名 -->
<mapper class="com.example.mapper.UserMapper"/>
<!-- 方式四:将包内的映射器接口全部注册为映射器 -->
<package name="com.example.mapper"/>
</mappers>推荐使用方式四(包扫描) ,自动注册指定包下的所有 Mapper 接口。
三、XML 映射文件详解
3.1 映射文件基本结构
<?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="com.example.mapper.UserMapper">
<!-- 结果映射 -->
<resultMap id="BaseResultMap" type="User">
<id property="id" column="id"/>
<result property="username" column="user_name"/>
<result property="password" column="password"/>
</resultMap>
<!-- SQL 片段 -->
<sql id="Base_Column_List">
id, user_name, password
</sql>
<!-- 查询 -->
<select id="selectById" resultMap="BaseResultMap">
SELECT <include refid="Base_Column_List"/>
FROM user WHERE id = #{id}
</select>
<!-- 插入 -->
<insert id="insert" parameterType="User"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (user_name, password)
VALUES (#{username}, #{password})
</insert>
<!-- 更新 -->
<update id="update" parameterType="User">
UPDATE user
SET user_name = #{username}, password = #{password}
WHERE id = #{id}
</update>
<!-- 删除 -->
<delete id="deleteById">
DELETE FROM user WHERE id = #{id}
</delete>
</mapper>3.2 resultMap 自定义结果映射
当数据库字段名与 Java 属性名不一致时,需要使用 <resultMap> 进行自定义映射。
<resultMap id="UserResultMap" type="com.example.model.User">
<!-- id 用于映射主键 -->
<id property="id" column="id"/>
<!-- result 用于映射普通字段 -->
<result property="username" column="user_name"/>
<result property="email" column="email_address"/>
<result property="createTime" column="create_time"/>
</resultMap>3.3 一对一关联映射(association)
一对一关联使用 <association> 标签。例如,一个学生对应一个班级:
<resultMap id="studentMapper" type="com.example.pojo.Student">
<id property="sid" column="sid"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="sex" column="sex"/>
<!-- 一对一对象映射 -->
<association property="classes" column="classId"
javaType="com.example.pojo.Classes">
<id property="cid" column="cid"/>
<result property="className" column="className"/>
</association>
</resultMap>
<select id="findAll" resultMap="studentMapper">
SELECT * FROM student
LEFT JOIN classes ON student.classId = classes.cid
</select>3.4 一对多关联映射(collection)
一对多关联使用 <collection> 标签。例如,一个班级对应多个学生:
<resultMap id="classesMapper" type="com.example.pojo.Classes">
<id property="cid" column="cid"/>
<result property="className" column="className"/>
<!-- 一对多集合映射 -->
<collection property="studentList" ofType="com.example.pojo.Student">
<id property="sid" column="sid"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
</collection>
</resultMap>
<select id="findClassesWithStudents" resultMap="classesMapper">
SELECT c.cid, c.class_name, s.sid, s.name, s.age
FROM classes c
LEFT JOIN student s ON c.cid = s.class_id
WHERE c.cid = #{cid}
</select>3.5 动态 SQL
动态 SQL 是 MyBatis 最强大的特性之一,可以根据不同条件动态生成 SQL 语句。
(1)if 标签
<select id="findActiveBlogWithTitleLike" resultType="Blog">
SELECT * FROM BLOG WHERE state = 'ACTIVE'
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>(2)choose/when/otherwise 标签(类似 Java 的 switch)
<select id="findActiveBlogLike" resultType="Blog">
SELECT * FROM BLOG WHERE state = 'ACTIVE'
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>(3)where 标签
<where> 只会在子元素有内容的情况下才插入 WHERE 子句,而且会自动去除子句开头的 AND 或 OR。
<select id="findUserByCondition" resultType="User">
SELECT * FROM users
<where>
<if test="name != null">
AND name = #{name}
</if>
<if test="age != null">
AND age = #{age}
</if>
</where>
</select>(4)set 标签(用于 UPDATE 语句)
<set> 会自动在 SQL 前添加 SET 关键字,并去除多余的逗号。
<update id="updateUser" parameterType="User">
UPDATE user
<set>
<if test="username != null">user_name = #{username},</if>
<if test="password != null">password = #{password},</if>
<if test="email != null">email = #{email},</if>
</set>
WHERE id = #{id}
</update>(5)foreach 标签
<foreach> 非常适合动态构建 IN 查询或处理批量操作。
<!-- IN 查询 -->
<select id="findByIds" resultType="User">
SELECT * FROM user WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<!-- 批量插入 -->
<insert id="batchInsert">
INSERT INTO user (user_name, password) VALUES
<foreach collection="users" item="user" separator=",">
(#{user.username}, #{user.password})
</foreach>
</insert><foreach> 标签的属性说明:
- collection:要遍历的集合,可以是 List、Set、Map、数组
- item:集合中每个元素的变量名
- open:开始符号
- separator:分隔符
- close:结束符号
(6)trim 标签
<trim> 标签可以自定义 SQL 片段的拼接,去除前缀或后缀,也可以替换特定的前缀或后缀。常用于替代 <where> 和 <set>:
<!-- 等价于 <where> -->
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
<!-- 等价于 <set> -->
<trim prefix="SET" suffixOverrides=",">
...
</trim>(7)sql 和 include 标签(SQL 片段复用)
<!-- 定义 SQL 片段 -->
<sql id="Base_Column_List">
id, user_name, password, email, create_time
</sql>
<!-- 引用 SQL 片段 -->
<select id="selectAll" resultMap="BaseResultMap">
SELECT <include refid="Base_Column_List"/> FROM user
</select>3.6 selectKey 获取自增主键
对于支持自增主键的数据库(如 MySQL),可以在 <insert> 中使用 useGeneratedKeys 和 keyProperty 获取插入后的主键值:
<insert id="insertUser" parameterType="User"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (user_name, password)
VALUES (#{username}, #{password})
</insert>对于不支持自增主键的数据库(如 Oracle),可以使用 <selectKey> 标签:
<insert id="insertUser" parameterType="User">
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="BEFORE">
SELECT SEQ_USER.NEXTVAL FROM DUAL
</selectKey>
INSERT INTO user (id, user_name, password)
VALUES (#{id}, #{username}, #{password})
</insert>对于 MySQL,使用 order="AFTER" 配合 SELECT LAST_INSERT_ID() 获取自增 ID:
<insert id="insertUser">
INSERT INTO user (user_name, password) VALUES (#{username}, #{password})
<selectKey keyProperty="id" resultType="int" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
</insert>四、注解方式开发
注解方式可以省去 XML 映射文件,直接在 Mapper 接口上用注解编写 SQL,代码更加简洁。
4.1 基础 CRUD 注解
MyBatis 提供了 @Select、@Insert、@Update、@Delete 四个核心注解:
@Mapper
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{id}")
User getUserById(int id);
@Insert("INSERT INTO users(name, email) VALUES(#{name}, #{email})")
void insertUser(User user);
@Update("UPDATE users SET name = #{name}, email = #{email} WHERE id = #{id}")
int updateUser(User user);
@Delete("DELETE FROM users WHERE id = #{id}")
int deleteUser(int id);
}4.2 @Param 注解(多参数传递)
当方法有多个参数时,需要使用 @Param 注解指定参数名:
@Select("SELECT * FROM user WHERE id = #{id} AND user_name = #{name}")
User getUserByIdAndName(@Param("id") Long id, @Param("name") String username);@Param 指定的参数名应与 SQL 中 #{} 的参数名一致。
4.3 @Results 和 @Result 注解(结果映射)
当数据库字段名与 Java 属性名不一致时,使用 @Results 和 @Result 解决:
@Select("SELECT * FROM user WHERE id = #{id}")
@Results({
@Result(property = "username", column = "user_name"),
@Result(property = "password", column = "password")
})
User getUser(Long id);4.4 @ResultMap 注解(引用 XML 中的 resultMap)
如果 XML 中已经定义了 <resultMap>,可以使用 @ResultMap 注解直接引用,减少重复代码:
@Select("SELECT * FROM user WHERE id = #{id}")
@ResultMap("BaseResultMap")
User getUser(Long id);4.5 @Options 注解(配置选项)
@Options 注解用于配置自定义默认行为,最常用的场景是获取自增主键:
@Insert("INSERT INTO users(name, email) VALUES(#{name}, #{email})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insertUser(User user);4.6 @One 和 @Many 注解(关联映射)
注解方式下,一对一使用 @One,一对多使用 @Many:
// 一对一:查询用户时同时查询其角色
@Select("SELECT * FROM user WHERE id = #{userId}")
@Results({
@Result(property = "id", column = "user_id"),
@Result(property = "username", column = "username"),
@Result(property = "role", column = "role_id",
one = @One(select = "com.example.mapper.RoleMapper.getRoleById"))
})
User getUserWithRole(int userId);4.7 @SelectKey 注解(获取主键)
@SelectKey(statement = "SELECT identity('users')", keyProperty = "id",
before = true, resultType = int.class)
@Insert("INSERT INTO users (id, name) VALUES(#{id}, #{name})")
boolean insert(User user);4.8 @Provider 注解(动态 SQL)
当注解中的 SQL 比较复杂时,可以使用 Provider 注解将 SQL 生成逻辑移到 Java 方法中。常见 Provider 注解包括 @SelectProvider、@InsertProvider、@UpdateProvider、@DeleteProvider
@SelectProvider(type = UserSqlProvider.class, method = "getUserByCondition")
User getUserByCondition(Map<String, Object> params);其中 UserSqlProvider 类中定义 getUserByCondition 方法动态生成 SQL 字符串。
4.9 @CacheNamespace 注解(注解方式开启二级缓存)
对于使用注解的 Mapper,在接口上使用 @CacheNamespace 注解即可启用二级缓存:
@CacheNamespace
@Mapper
public interface UserMapper {
// ...
}五、Spring Boot 集成 MyBatis
5.1 依赖导入
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>mybatis-spring-boot-starter 已经集成了 mybatis 和 mybatis-spring 的依赖,无需单独引入。
5.2 application.yml 配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_db?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
hikari:
maximum-pool-size: 10
max-lifetime: 1770000
mybatis:
# 指定别名设置的包
type-aliases-package: com.example.entity
# mapper映射文件位置
mapper-locations:
- classpath:mapper/*.xml
# 全局配置
configuration:
map-underscore-to-camel-case: true
cache-enabled: true
lazy-loading-enabled: true
aggressive-lazy-loading: false
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl其中 map-underscore-to-camel-case: true 开启了驼峰命名规范,数据库字段 user_name 会自动映射到实体类的 userName 属性。
5.3 application.properties 配置(等价写法)
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_db
spring.datasource.username=root
spring.datasource.password=123456
mybatis.type-aliases-package=com.example.entity
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.cache-enabled=true5.4 @MapperScan 注解
在 Spring Boot 启动类上使用 @MapperScan 注解,自动扫描 Mapper 接口:
@SpringBootApplication
@MapperScan("com.example.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}六、缓存机制
MyBatis 提供两级缓存:一级缓存和二级缓存。
6.1 一级缓存(SqlSession 级别)
一级缓存默认开启,是 SqlSession 级别的缓存,只对当前 SqlSession 有效。当 SqlSession 关闭或提交时,一级缓存会被清空。当在同一个 SqlSession 中执行相同的查询时,第二次查询会直接从缓存中获取结果,不会访问数据库。
6.2 二级缓存(namespace 级别)
二级缓存需要手动开启,是基于 namespace 级别的缓存,可以被多个 SqlSession 共享。
开启步骤:
第一步:在 mybatis-config.xml 中全局开启(默认已开启)
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>在 Spring Boot 的 yml 中:
mybatis:
configuration:
cache-enabled: true第二步:在 Mapper XML 中配置 <cache> 标签
<mapper namespace="com.example.mapper.UserMapper">
<!-- 开启当前 Mapper 的二级缓存 -->
<cache eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
<select id="selectById" resultMap="BaseResultMap" useCache="true">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper><cache> 标签的属性说明:
| 属性 | 说明 | 默认值 |
|---|---|---|
| eviction | 缓存回收策略(LRU/FIFO/SOFT/WEAK) | LRU |
| flushInterval | 刷新间隔(毫秒),不设置则仅在调用语句时刷新 | 无 |
| size | 缓存最多存储的对象个数 | 1024 |
| readOnly | 是否只读 | false |
注解方式开启二级缓存:
7.1 两种参数获取方式
MyBatis 获取参数值有两种方式:#{} 和 ${}。
| 特性 | #{} | ${} |
|---|---|---|
| 本质 | 占位符赋值(PreparedStatement 参数) | 字符串拼接 |
| SQL 注入风险 | 无 | 有 |
| 字符串类型自动加引号 | 是 | 否(需手动加) |
| 适用场景 | 参数值传递 | 动态表名、列名、排序字段 |
#{} 使用的是预编译 SQL,通过占位符 ? 赋值,可以防止 SQL 注入;${} 是直接进行字符串替换,存在 SQL 注入风险。
7.2 各种参数类型的使用
单个字面量类型参数: 可以使用任意名称获取值
@Select("SELECT * FROM user WHERE id = #{id}")
User getUserById(Long id);
// 或
@Select("SELECT * FROM user WHERE id = #{value}")
User getUserById(Long id);多个字面量类型参数: 需要使用 @Param 注解
@Select("SELECT * FROM user WHERE id = #{id} AND name = #{name}")
User getUser(@Param("id") Long id, @Param("name") String name);实体类类型参数: 直接使用属性名
@Insert("INSERT INTO user (name, age) VALUES (#{name}, #{age})")
void insertUser(User user);Map 类型参数: 使用 Map 的 key
@Select("SELECT * FROM user WHERE id = #{userId} AND name = #{userName}")
User getUser(Map<String, Object> map);推荐做法:无论参数多少,统一使用 @Param 标注参数名称,避免使用 arg0、arg1、param1 等自动生成的名称。
八、延迟加载
延迟加载(懒加载)是指在使用关联对象时才去执行查询,而不是在查询主对象时就立即加载。这可以减少不必要的数据库查询。
配置方式:
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>- lazyLoadingEnabled:开启延迟加载的全局开关
- aggressiveLazyLoading:设置为 false 时按需加载,设置为 true 时任何属性的调用都会加载该对象的所有属性
在 Spring Boot 的 yml 中:
mybatis:
configuration:
lazy-loading-enabled: true
aggressive-lazy-loading: false在特定的关联关系上可以通过 fetchType 属性覆盖全局设置:
<association property="classes" javaType="Classes"
select="selectClassesById" column="classId"
fetchType="lazy">
</association>九、常见问题与最佳实践
9.1 字段映射问题
当数据库使用下划线命名(如 user_name),Java 使用驼峰命名(如 userName)时,解决方案有三种:
- 开启自动驼峰映射(推荐):在配置中设置 map-underscore-to-camel-case: true
- 使用 resultMap:在 XML 中自定义映射关系
- 使用 @Results 注解:在注解中定义映射关系
9.2 #{} 和 ${} 的选择
优先选择 #{},它可以防止 SQL 注入。只有在以下场景才使用 ${}:
- 动态表名:SELECT * FROM ${tableName}
- 动态列名:ORDER BY ${columnName}
- 动态排序方向:ORDER BY id ${order}
9.3 注解和 XML 的选择
实际项目中,XML 和注解常结合使用。XML 适合管理复杂的 SQL 和结果映射,注解适合简单的 CRUD 操作。推荐的做法是:简单查询用注解,复杂 SQL 和动态 SQL 用 XML,两者混用可以互补。
9.4 事务管理
在 Spring Boot 中,使用 @Transactional 注解管理事务:
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional
public void batchInsertUsers(List<User> users) {
for (User user : users) {
userMapper.insertUser(user);
}
}
}9.5 日志配置
在开发阶段开启 SQL 日志输出,方便调试:
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl或在 application.properties 中配置指定包的日志级别:
logging.level.com.example.mapper=DEBUG以上教程涵盖了 MyBatis 的核心配置文件、XML 映射文件、注解开发、Spring Boot 集成、动态 SQL、关联映射、缓存机制、延迟加载和参数传递等主要内容。建议从核心配置文件和基础 CRUD 开始学习,逐步深入到动态 SQL、关联映射和缓存等高级特性。