MyBatis完全学习指南
目录
1. MyBatis简介
1.1 什么是MyBatis?
1.2 MyBatis架构
1.3 MyBatis与其他持久层框架对比
2. 环境搭建与配置
2.1 Maven依赖配置
2.2 项目结构
3. 核心配置文件详解
3.1 mybatis-config.xml主配置文件
3.2 database.properties配置文件
3.3 重要设置详解
4. 映射文件(Mapper)详解
4.1 基本映射文件结构
4.2 实体类示例
4.3 Mapper接口
5. 基本CRUD操作
5.1 查询操作(Select)
5.2 插入操作(Insert)
5.3 更新操作(Update)
5.4 删除操作(Delete)
5.5 使用示例
6. 参数传递详解
6.1 单个参数
6.2 多个参数
方式1:使用@Param注解(推荐)
方式2:使用Map传参
方式3:使用实体对象传参
6.3 集合参数
7. 结果映射详解
7.1 基础结果映射
自动映射(列名与属性名一致)
列名与属性名不一致的处理
7.2 自定义结果映射(ResultMap)
7.3 复杂对象映射
一对一关联
一对多关联
7.4 分步查询(延迟加载)
8. 动态SQL详解
8.1 if标签
8.2 where标签
8.3 choose、when、otherwise标签
8.4 trim标签
8.5 set标签
8.6 foreach标签
8.7 bind标签
8.8 sql标签和include标签
9. 缓存机制
9.1 一级缓存(SqlSession级别)
9.2 二级缓存(Mapper级别)
开启二级缓存
二级缓存配置详解
控制缓存行为
9.3 自定义缓存
集成EhCache
9.4 缓存最佳实践
10. 注解开发
10.1 基本CRUD注解
10.2 复杂查询注解
动态SQL
SQL提供者类
10.3 关联映射注解
一对一关联
一对多关联
10.4 注解配置缓存
10.5 混合使用XML和注解
11. 插件机制
11.1 插件工作原理
11.2 自定义插件示例
SQL执行时间监控插件
分页插件
11.3 插件注册
在mybatis-config.xml中注册
使用示例
11.4 常用开源插件
PageHelper分页插件
12. 与Spring集成
12.1 Spring配置方式
Maven依赖
Spring配置文件
12.2 Spring Boot配置方式
依赖配置
application.yml配置
启动类配置
12.3 Service层实现
12.4 Controller层实现
13. 最佳实践与常见问题
13.1 最佳实践
命名规范
性能优化
代码组织
13.2 常见问题及解决方案
问题1:参数传递问题
问题2:结果映射问题
问题3:SQL注入问题
问题4:事务失效问题
问题5:缓存问题
问题6:连接池配置问题
13.3 调试技巧
开启SQL日志
使用MyBatis日志插件
性能监控
总结
优点
适用场景
学习建议
1. MyBatis简介
1.1 什么是MyBatis?
MyBatis是一个优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。MyBatis免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作。
核心特点:
- 简单易学:本身就很小且简单
- 灵活:不会对应用程序或者数据库的现有设计强加任何影响
- 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离
- 支持动态SQL:根据不同条件拼接SQL语句
1.2 MyBatis架构
应用程序↓
SqlSession (会话)↓
Executor (执行器)↓
StatementHandler (语句处理器)↓
ParameterHandler (参数处理器) → ResultSetHandler (结果处理器)↓
JDBC↓
数据库
1.3 MyBatis与其他持久层框架对比
特性 | MyBatis | Hibernate | JPA |
---|---|---|---|
学习难度 | 简单 | 复杂 | 中等 |
SQL控制 | 完全控制 | 部分控制 | 部分控制 |
性能优化 | 容易 | 复杂 | 中等 |
开发效率 | 中等 | 高 | 高 |
2. 环境搭建与配置
2.1 Maven依赖配置
<!-- pom.xml -->
<dependencies><!-- MyBatis核心依赖 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.13</version></dependency><!-- 数据库驱动,以MySQL为例 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><!-- 日志依赖(可选) --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.36</version></dependency>
</dependencies>
2.2 项目结构
src/main/java/
├── com/example/
│ ├── entity/ # 实体类
│ ├── mapper/ # Mapper接口
│ ├── service/ # 业务层
│ └── utils/ # 工具类
src/main/resources/
├── mybatis-config.xml # MyBatis主配置文件
├── mapper/ # SQL映射文件
└── log4j.properties # 日志配置
3. 核心配置文件详解
3.1 mybatis-config.xml主配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- 属性配置 --><properties resource="database.properties"/><!-- 设置 --><settings><!-- 开启驼峰命名转换 --><setting name="mapUnderscoreToCamelCase" value="true"/><!-- 开启延迟加载 --><setting name="lazyLoadingEnabled" value="true"/><!-- 设置超时时间 --><setting name="defaultStatementTimeout" value="30"/><!-- 开启二级缓存 --><setting name="cacheEnabled" value="true"/></settings><!-- 类型别名 --><typeAliases><!-- 单个别名 --><typeAlias type="com.example.entity.User" alias="User"/><!-- 包扫描 --><package name="com.example.entity"/></typeAliases><!-- 类型处理器 --><typeHandlers><typeHandler handler="com.example.handler.MyTypeHandler"/></typeHandlers><!-- 环境配置 --><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></environments><!-- 映射器 --><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>
</configuration>
3.2 database.properties配置文件
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
jdbc.username=root
jdbc.password=123456
3.3 重要设置详解
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
mapUnderscoreToCamelCase | 开启驼峰命名转换 | true/false | false |
lazyLoadingEnabled | 延迟加载的全局开关 | true/false | false |
cacheEnabled | 全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存 | true/false | true |
defaultStatementTimeout | 设置超时时间 | 任意正整数 | 未设置 |
4. 映射文件(Mapper)详解
4.1 基本映射文件结构
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper"><!-- 这里写SQL映射 -->
</mapper>
4.2 实体类示例
public class User {private Long id;private String username;private String password;private String email;private Date createTime;// 构造方法public User() {}public User(String username, String password, String email) {this.username = username;this.password = password;this.email = email;}// getter和setter方法public Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getUsername() { return username; }public void setUsername(String username) { this.username = username; }// ... 其他getter/setter方法@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +", email='" + email + '\'' +", createTime=" + createTime +'}';}
}
4.3 Mapper接口
public interface UserMapper {// 根据ID查询用户User selectById(Long id);// 查询所有用户List<User> selectAll();// 添加用户int insert(User user);// 更新用户int update(User user);// 删除用户int deleteById(Long id);// 根据用户名查询User selectByUsername(String username);// 分页查询List<User> selectByPage(@Param("offset") int offset, @Param("limit") int limit);
}
5. 基本CRUD操作
5.1 查询操作(Select)
<!-- 根据ID查询用户 -->
<select id="selectById" resultType="User">SELECT id, username, password, email, create_timeFROM user WHERE id = #{id}
</select><!-- 查询所有用户 -->
<select id="selectAll" resultType="User">SELECT id, username, password, email, create_timeFROM userORDER BY create_time DESC
</select><!-- 根据用户名查询 -->
<select id="selectByUsername" resultType="User">SELECT id, username, password, email, create_timeFROM user WHERE username = #{username}
</select><!-- 分页查询 -->
<select id="selectByPage" resultType="User">SELECT id, username, password, email, create_timeFROM userORDER BY create_time DESCLIMIT #{offset}, #{limit}
</select>
5.2 插入操作(Insert)
<!-- 插入用户 -->
<insert id="insert" parameterType="User">INSERT INTO user(username, password, email, create_time)VALUES(#{username}, #{password}, #{email}, NOW())
</insert><!-- 插入用户并返回主键 -->
<insert id="insertAndReturnKey" parameterType="User" useGeneratedKeys="true" keyProperty="id">INSERT INTO user(username, password, email, create_time)VALUES(#{username}, #{password}, #{email}, NOW())
</insert><!-- 批量插入 -->
<insert id="insertBatch" parameterType="list">INSERT INTO user(username, password, email, create_time)VALUES<foreach collection="list" item="user" separator=",">(#{user.username}, #{user.password}, #{user.email}, NOW())</foreach>
</insert>
5.3 更新操作(Update)
<!-- 更新用户 -->
<update id="update" parameterType="User">UPDATE user SET username = #{username},password = #{password},email = #{email}WHERE id = #{id}
</update><!-- 动态更新(只更新不为空的字段) -->
<update id="updateSelective" parameterType="User">UPDATE user<set><if test="username != null and username != ''">username = #{username},</if><if test="password != null and password != ''">password = #{password},</if><if test="email != null and email != ''">email = #{email},</if></set>WHERE id = #{id}
</update>
5.4 删除操作(Delete)
<!-- 根据ID删除用户 -->
<delete id="deleteById" parameterType="long">DELETE FROM user WHERE id = #{id}
</delete><!-- 批量删除 -->
<delete id="deleteBatch" parameterType="list">DELETE FROM user WHERE id IN<foreach collection="list" item="id" open="(" separator="," close=")">#{id}</foreach>
</delete><!-- 根据条件删除 -->
<delete id="deleteByCondition">DELETE FROM user WHERE create_time < #{beforeDate}
</delete>
5.5 使用示例
public class UserService {private SqlSession sqlSession;private UserMapper userMapper;public UserService() {// 获取SqlSessionsqlSession = MyBatisUtils.getSqlSession();userMapper = sqlSession.getMapper(UserMapper.class);}// 查询用户public User getUserById(Long id) {return userMapper.selectById(id);}// 添加用户public boolean addUser(User user) {try {int result = userMapper.insert(user);sqlSession.commit(); // 提交事务return result > 0;} catch (Exception e) {sqlSession.rollback(); // 回滚事务e.printStackTrace();return false;}}// 关闭资源public void close() {if (sqlSession != null) {sqlSession.close();}}
}
6. 参数传递详解
6.1 单个参数
<!-- 基本类型参数 -->
<select id="selectById" resultType="User">SELECT * FROM user WHERE id = #{id}
</select><!-- 字符串参数 -->
<select id="selectByUsername" resultType="User">SELECT * FROM user WHERE username = #{username}
</select>
// 接口方法
User selectById(Long id);
User selectByUsername(String username);
6.2 多个参数
方式1:使用@Param注解(推荐)
// 接口方法
List<User> selectByUsernameAndEmail(@Param("username") String username, @Param("email") String email);
<select id="selectByUsernameAndEmail" resultType="User">SELECT * FROM user WHERE username = #{username} AND email = #{email}
</select>
方式2:使用Map传参
// 接口方法
List<User> selectByMap(Map<String, Object> params);
<select id="selectByMap" resultType="User">SELECT * FROM user WHERE username = #{username} AND email = #{email}
</select>
// 使用示例
Map<String, Object> params = new HashMap<>();
params.put("username", "admin");
params.put("email", "admin@example.com");
List<User> users = userMapper.selectByMap(params);
方式3:使用实体对象传参
// 查询条件实体
public class UserQuery {private String username;private String email;private Date startDate;private Date endDate;// getter/setter...
}// 接口方法
List<User> selectByQuery(UserQuery query);
<select id="selectByQuery" resultType="User">SELECT * FROM user WHERE 1=1<if test="username != null and username != ''">AND username LIKE CONCAT('%', #{username}, '%')</if><if test="email != null and email != ''">AND email = #{email}</if><if test="startDate != null">AND create_time >= #{startDate}</if><if test="endDate != null">AND create_time <= #{endDate}</if>
</select>
6.3 集合参数
// 接口方法
List<User> selectByIds(@Param("ids") List<Long> ids);
int deleteBatch(@Param("ids") List<Long> ids);
<!-- 根据ID列表查询 -->
<select id="selectByIds" resultType="User">SELECT * FROM user WHERE id IN<foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach>
</select><!-- 批量删除 -->
<delete id="deleteBatch">DELETE FROM user WHERE id IN<foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach>
</delete>
7. 结果映射详解
7.1 基础结果映射
自动映射(列名与属性名一致)
<select id="selectById" resultType="User">SELECT id, username, password, email FROM user WHERE id = #{id}
</select>
列名与属性名不一致的处理
方式1:使用别名
<select id="selectById" resultType="User">SELECT id,username,password,email,create_time AS createTimeFROM user WHERE id = #{id}
</select>
方式2:开启驼峰命名转换
<!-- mybatis-config.xml中配置 -->
<setti