MyBatis 动态 SQL 完整笔记
MyBatis 动态 SQL 完整笔记
一、核心动态 SQL 标签与用法
1. 条件控制类标签
-
<if>
:基础条件判断
示例:根据name
和age
动态筛选用户<if test="name != null and name != ''">AND user_name = #{name} </if>
-
<choose>/<when>/<otherwise>
:多条件分支
示例:类似 Java 的switch-case
,优先匹配首个满足条件的<when>
<choose><when test="type == 'admin'">AND role = 'admin'</when><otherwise>AND role = 'guest'</otherwise> </choose>
2. 语法修正类标签
-
<where>
:自动处理WHERE
关键字和首条条件前的AND/OR
<where><if test="age != null">AND age = #{age}</if> </where>
-
<trim>
:更灵活的语法修正(替代<where>
或<set>
)
示例:自定义前缀/后缀及需删除的字符<trim prefix="WHERE" prefixOverrides="AND |OR"><if test="name != null">AND name=#{name}</if> </trim>
-
<set>
:自动处理UPDATE
语句的SET
子句
示例:动态更新字段并去除末尾逗号<set><if test="name != null">name=#{name},</if><if test="age != null">age=#{age}</if> </set>
3. 集合处理类标签
-
<foreach>
:遍历集合(批量操作/IN 查询)<foreach collection="list" item="item" open="(" separator="," close=")">#{item.id} </foreach>
-
<bind>
:预定义变量(优化模糊查询等场景)<bind name="namePattern" value="'%' + name + '%'"/> WHERE username LIKE #{namePattern}
二、性能优化与最佳实践
1. OGNL 表达式优化
- 避免复杂嵌套表达式,优先在 Java 层处理判断逻辑
<if test="@com.utils.MyBatisUtils@isValid(name)">
2. 批量操作优化
- 使用
BATCH
模式执行SqlSession
,减少数据库连接开销 - 分批次处理超大数据集(如每 1000 条提交一次)
3. 缓存策略
- 二级缓存配置(Mapper 级别,跨会话共享)
<mapper namespace="com.UserMapper"><cache eviction="LRU" flushInterval="60000"/> </mapper>
- 注意脏读问题:更新操作后手动清除缓存
<update id="updateUser" flushCache="true">
三、高频场景实战示例
1. 动态排序与分页
<select id="selectUsers" resultMap="UserResultMap">SELECT * FROM users<where><if test="orderBy != null">ORDER BY ${orderBy} <!-- 注意 SQL 注入风险 --></if><if test="offset >=0 and limit >0">LIMIT #{offset}, #{limit}</if></where>
</select>
2. 多字段模糊查询
<bind name="searchKey" value="'%' + key + '%'"/>
<where>(title LIKE #{searchKey} OR content LIKE #{searchKey})
</where>
3. 批量插入优化
<insert id="batchInsert">INSERT INTO users (name, age) VALUES<foreach collection="list" item="user" separator=",">(#{user.name}, #{user.age})</foreach>ON DUPLICATE KEY UPDATE age=VALUES(age)
</insert>
四、安全与规范
1. 防 SQL 注入
- 禁止直接拼接
${}
参数(除非绝对可信) - 使用
#{}
预编译参数化查询
2. 参数校验
- 集合判空:
<if test="list != null and !list.isEmpty()">
- 字符串处理:
<if test="name != null and name.trim() != ''">
3. 类型安全
- 显式声明
jdbcType
(避免 NULL 类型推断错误)#{age,jdbcType=INTEGER}
五、高级特性
1. 注解动态 SQL
@SelectProvider(type = UserSqlBuilder.class, method = "buildQuery")
List<User> findUsers(UserQuery query);
2. 动态表名映射
<select id="selectByTable" resultType="map">SELECT * FROM ${tableName}
</select>
最佳实践总结
- 优先使用
<where>
/<set>
替代手动处理 SQL 语法- 复杂条件判断应前移至 Java 代码处理
- 批量操作需配合数据库连接池优化
- 高频读场景启用二级缓存,但注意数据一致性
- 使用
<bind>
统一处理格式转换(如日期/模糊查询)