第06章 Mapper接口
掌握 Mapper 接口的使用和接口映射机制
学习进度:24%
💻 查看完整代码 - 在线IDE体验
🎯 学习目标
📚
理解核心概念
掌握本章的核心概念和基本原理
🔧
掌握实践技能
学会相关的配置方法和实践技巧
💡
了解应用场景
明确在实际项目中的应用场景和最佳实践
学习目标
深入理解MyBatis Mapper接口的概念和作用
掌握XML映射和注解映射两种方式
了解Mapper代理机制的工作原理
学会定义和使用各种Mapper方法
掌握参数传递和结果处理的技巧
Mapper接口概述
Mapper接口是MyBatis的核心组件,它定义了数据访问的方法签名,MyBatis会自动为这些接口创建代理实现,将方法调用转换为SQL执行。
Mapper接口的优势
类型安全:编译时检查方法签名和参数类型
代码简洁:无需编写实现类,只需定义接口
易于维护:接口与SQL映射分离,便于管理
IDE支持:完整的代码提示和重构支持
XML映射方式
1. 定义Mapper接口
package com.example.mybatis.mapper;
import com.example.mybatis.model.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface UserMapper {
// 查询所有用户
List
// 根据ID查询用户
User selectUserById(Long id);
// 根据年龄查询用户
List
// 条件查询
List
// 统计用户数量
long countUsers();
// 插入用户
int insertUser(User user);
// 更新用户
int updateUser(User user);
// 删除用户
int deleteUser(Long id);
}
2. 创建XML映射文件
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
SELECT id, name, age, email FROM users
SELECT id, name, age, email FROM users WHERE id = #{id}
SELECT id, name, age, email FROM users WHERE age = #{age}
SELECT COUNT(*) FROM users
useGeneratedKeys="true" keyProperty="id"> INSERT INTO users (name, age, email) VALUES (#{name}, #{age}, #{email})
UPDATE users SET name = #{name}, age = #{age}, email = #{email}
WHERE id = #{id}
DELETE FROM users WHERE id = #{id}
3. 配置映射文件
注解映射方式
1. 基本注解
@Mapper
public interface UserAnnotationMapper {
@Select("SELECT id, name, age, email FROM users")
List
@Select("SELECT id, name, age, email FROM users WHERE id = #{id}")
User findUserById(@Param("id") Long id);
@Insert("INSERT INTO users(name, age, email) VALUES(#{name}, #{age}, #{email})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insertUser(User user);
@Update("UPDATE users SET name = #{name}, age = #{age}, email = #{email} WHERE id = #{id}")
int updateUser(User user);
@Delete("DELETE FROM users WHERE id = #{id}")
int deleteUser(@Param("id") Long id);
@Select("SELECT COUNT(*) FROM users")
long countUsers();
}
2. 结果映射注解
@Select("SELECT id, name, age, email FROM users")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "age", column = "age"),
@Result(property = "email", column = "email")
})
List
3. 动态SQL注解
@SelectProvider(type = UserSqlProvider.class, method = "selectUsersByCondition")
List
// SQL提供者类
class UserSqlProvider {
public String selectUsersByCondition(@Param("name") String name, @Param("minAge") Integer minAge) {
StringBuilder sql = new StringBuilder("SELECT id, name, age, email FROM users WHERE 1=1");
if (name != null && !name.isEmpty()) {
sql.append(" AND name LIKE CONCAT('%', #{name}, '%')");
}
if (minAge != null) {
sql.append(" AND age >= #{minAge}");
}
return sql.toString();
}
}
Mapper代理机制
1. 代理对象的创建
// MyBatis自动创建代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 查看代理对象信息
System.out.println("Mapper接口类型: " + userMapper.getClass().getName());
System.out.println("是否为代理对象: " + userMapper.getClass().getName().contains("Proxy"));
2. 方法调用流程
调用Mapper接口方法
代理对象拦截方法调用
根据方法名查找对应的SQL语句
执行SQL并处理结果
返回处理后的结果
参数传递
1. 单个参数
// 接口定义
User selectUserById(Long id);
// XML映射
SELECT * FROM users WHERE id = #{id}
2. 多个参数(使用@Param)
// 接口定义
List
@Param("maxAge") Integer maxAge);
// XML映射
SELECT * FROM users WHERE age BETWEEN #{minAge} AND #{maxAge}
3. 对象参数
// 接口定义
int insertUser(User user);
// XML映射
INSERT INTO users (name, age, email)
VALUES (#{name}, #{age}, #{email})
4. Map参数
// 接口定义
List
// XML映射
SELECT * FROM users
AND name LIKE CONCAT('%', #{name}, '%')
AND age >= #{minAge}
返回值处理
1. 基本类型返回值
// 返回数量
long countUsers();
// 返回影响行数
int insertUser(User user);
int updateUser(User user);
int deleteUser(Long id);
2. 对象返回值
// 返回单个对象
User selectUserById(Long id);
// 返回对象列表
List
3. Map返回值
// 返回Map
@MapKey("id")
Map
// 返回单行Map
Map
最佳实践
1. 接口设计原则
方法名要清晰表达业务意图
参数类型要明确,避免使用Object
返回值类型要准确,避免过度包装
合理使用@Param注解标识参数
2. XML vs 注解选择
简单SQL:使用注解,代码更简洁
复杂SQL:使用XML,可读性更好
动态SQL:推荐使用XML
团队规范:保持一致的风格
3. 性能优化
合理设计方法签名,避免不必要的数据传输
使用合适的返回值类型
避免在Mapper中进行复杂的业务逻辑
合理使用批量操作方法
常见问题与解决方案
Q: Mapper接口方法找不到对应的SQL语句?
A: 检查namespace是否正确,方法名是否与SQL语句的id一致。
Q: 多个参数时出现参数绑定错误?
A: 使用@Param注解明确指定参数名称。
Q: 如何处理返回null的情况?
A: 在业务层进行null检查,或者使用Optional包装返回值。
Q: 注解和XML映射可以混合使用吗?
A: 可以,但建议在同一个项目中保持一致的风格。
实践练习
练习1:基本Mapper接口
创建一个完整的UserMapper接口,包含CRUD操作和统计方法。
练习2:注解映射
使用注解方式重新实现UserMapper的部分方法。
练习3:复杂参数传递
实现一个支持多条件查询的方法,使用Map传递参数。
练习4:批量操作
实现批量插入和批量删除的Mapper方法。
运行示例程序
步骤1:导入项目
将chapter-06-mapper-interface.json导入到IntelliJ IDEA中。
步骤2:配置数据库
确保MySQL数据库运行正常,执行init.sql创建测试数据。
步骤3:运行程序
运行MapperInterfaceDemo.java,观察不同映射方式的执行效果。
步骤4:查看结果
程序将演示XML映射器、注解映射器、Mapper方法和代理机制的使用。