mybatis mapper(长文解析)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
理解 MyBatis Mapper 的核心概念
在 Java 开发中,MyBatis 是一个广泛使用的持久层框架,而 Mapper 是其核心组件之一。我们可以将 Mapper 比作数据库与业务代码之间的“翻译官”:它负责将面向对象的 Java 代码转换为 SQL 语句,并将查询结果重新组装成 Java 对象。这种设计既保留了 SQL 的灵活性,又降低了直接操作数据库的复杂度。
Mapper 的三要素
- 接口(Interface):定义数据访问方法,如
selectById()
、insertUser()
- XML/注解配置:编写 SQL 语句并映射到接口方法
- 映射关系:将数据库字段与 Java 对象属性关联
例如,当我们需要查询用户信息时,只需调用 Mapper 接口中的方法,而具体的 SQL 语句和结果处理由 MyBatis 自动完成。这种分离设计使得代码更清晰,也便于维护。
MyBatis Mapper 的配置与使用步骤
步骤 1:创建 Mapper 接口
public interface UserMapper {
User selectById(Long id);
int insertUser(User user);
int updateUser(User user);
}
步骤 2:编写 XML 映射文件
<!-- resources/mapper/UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
<select id="selectById" resultType="User">
SELECT * FROM users WHERE id = #{id}
</select>
<insert id="insertUser">
INSERT INTO users (name, email) VALUES (#{name}, #{email})
</insert>
</mapper>
步骤 3:配置 MyBatis 配置文件
<configuration>
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
</configuration>
关键点说明
namespace
必须与接口全限定名一致id
属性对应接口方法名resultType
指定返回对象类型
MyBatis Mapper 的动态 SQL 实战
在实际开发中,SQL 语句往往需要根据条件动态变化。MyBatis 提供了 <if>
, <choose>
, <foreach>
等标签实现这一需求。
案例:多条件查询
<select id="searchUsers" resultType="User">
SELECT * FROM users
WHERE 1=1
<if test="name != null">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
<if test="age != null">
AND age >= #{age}
</if>
</select>
对比传统写法
// 传统拼接方式存在 SQL 注入风险
String sql = "SELECT * FROM users WHERE 1=1";
if (name != null) {
sql += " AND name LIKE '%" + name + "%'";
}
if (age != null) {
sql += " AND age >= " + age;
}
MyBatis Mapper 的高级用法解析
1. 关联查询(One-to-Many)
<!-- 用户与订单的关联查询 -->
<select id="findUserWithOrders" resultType="User">
SELECT
u.id,
u.name,
o.order_id,
o.amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.id = #{id}
</select>
<!-- 使用 resultMap 映射复杂关系 -->
<resultMap id="userResultMap" type="User">
<id property="id" column="id"/>
<collection property="orders" ofType="Order">
<id property="orderId" column="order_id"/>
<result property="amount" column="amount"/>
</collection>
</resultMap>
2. 缓存机制优化
<cache eviction="FIFO" flushInterval="60000"/>
缓存类型对比
| 缓存类型 | 作用范围 | 数据共享性 |
|----------------|----------------|------------|
| 命令缓存 | 会话级 | 不共享 |
| 二级缓存 | Mapper 级 | 同一命名空间共享 |
| 本地缓存 | 语句执行器级 | 单次会话内共享 |
MyBatis Mapper 的优化技巧
1. 避免 N+1 问题
<!-- 使用延迟加载 -->
<association property="department" column="dept_id"
javaType="Department" select="selectDepartmentById"
fetchType="lazy"/>
2. 分页策略
<!-- 原生分页 -->
<select id="selectUsers" resultType="User">
SELECT * FROM users
LIMIT #{offset}, #{limit}
</select>
<!-- 分页助手插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.0</version>
</dependency>
3. 预编译语句优化
<insert id="batchInsert">
INSERT INTO users (name, email) VALUES
<foreach collection="list" item="user" separator=",">
(#{user.name}, #{user.email})
</foreach>
</insert>
MyBatis Mapper 的常见问题与解决方案
问题 1:字段名与属性名不一致
<!-- 显式映射字段 -->
<resultMap id="userMap" type="User">
<result property="userName" column="user_name"/>
</resultMap>
问题 2:批量操作性能问题
// 使用批处理
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
for (User user : userList) {
mapper.insertUser(user);
}
sqlSession.commit();
} finally {
sqlSession.close();
}
问题 3:SQL 注入风险
<!-- 使用 #{} 预编译参数 -->
<update id="updateUser">
UPDATE users
SET name = #{name}
WHERE id = #{id}
</update>
结论:掌握 MyBatis Mapper 的核心价值
通过本文的系统讲解,我们看到 MyBatis Mapper 是连接业务逻辑与数据库的关键桥梁。它通过接口定义、XML/注解配置、结果映射三者结合,实现了数据访问的清晰分层。在实际项目中,开发者需要:
- 规范命名:保持接口方法与 SQL 语句的语义一致性
- 善用缓存:根据业务场景选择合适的缓存策略
- 动态 SQL:通过 MyBatis 提供的标签构建灵活查询
- 性能优化:结合分页、批处理等技术提升系统吞吐量
随着对 MyBatis Mapper 的深入理解,开发者不仅能编写出高效可靠的数据库访问代码,更能为后续的微服务拆分、分布式事务处理等复杂场景打下坚实基础。建议读者通过实际项目不断实践,逐步掌握这一核心技术。