
目录
- 一、 什么是动态 SQL?
- 二、 为什么需要动态 SQL?
- 三、 MyBatis 动态 SQL 标签
- 四、 标签详解及示例
- 1、 if 标签
- 2、 choose、when、otherwise 标签
- 3、 where 标签
- 4、 set 标签
- 5、 foreach 标签
- 6、 sql、include 标签
- 五、 总结
🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,可以多多支持一下,感谢🤗!
🌟了解 MyBatis 结果映射 请看 : MyBatis 结果映射详解!
其他优质专栏: 【🎇SpringBoot】【🎉多线程】【🎨Redis】【✨设计模式专栏(已完结)】…等
如果喜欢作者的讲解方式,可以点赞收藏加关注,你的支持就是我的动力
✨更多文章请看个人主页: 码熔burning
这篇文章让我来好好讲解一下 MyBatis 的动态 SQL。
一、 什么是动态 SQL?
动态 SQL 是指在 SQL 语句中,根据不同的条件或参数,生成不同的 SQL 语句。 💡 在传统的 SQL 语句中,SQL 语句是固定的,无法根据不同的情况进行变化。 而动态 SQL 可以根据不同的条件,动态地拼接 SQL 语句,从而满足不同的查询需求。
MyBatis 提供了强大的动态 SQL 功能,允许你根据运行时条件构建 SQL 语句。这使得你可以编写更灵活、可维护的 SQL 映射。
二、 为什么需要动态 SQL?
- 灵活性: 能够根据不同的条件生成不同的 SQL 语句,满足不同的查询需求。 🚀
- 可维护性: 将 SQL 语句的逻辑与 Java 代码分离,使代码更易于维护。
- 避免冗余: 避免编写大量的重复 SQL 语句,提高代码的复用性。
- 性能优化: 可以根据不同的条件选择不同的索引,提高查询效率。 📈
三、 MyBatis 动态 SQL 标签
MyBatis 提供了一系列标签来构建动态 SQL。 以下是常用的标签及其用法:
<if>: 条件判断<choose>、<when>、<otherwise>: 多条件选择<where>: 智能WHERE子句<set>: 智能SET子句<foreach>: 循环遍历<sql>、<include>: SQL 片段重用
四、 标签详解及示例
1、 if 标签
<if> 标签用于进行条件判断。 只有当 test 属性中的表达式为 true 时,才会将标签内的 SQL 片段添加到最终的 SQL 语句中。
<select id="findUsersByCondition" parameterType="map" resultType="User">SELECT * FROM usersWHERE 1=1 <!-- 避免第一个条件前出现 AND/OR --><if test="username != null and username != ''">AND username LIKE #{username}</if><if test="email != null and email != ''">AND email = #{email}</if>
</select>
解释:
id="findUsersByCondition":定义了一个名为findUsersByCondition的查询。parameterType="map":指定参数类型为map,这意味着你可以传递一个Map对象作为参数。resultType="User":指定结果类型为User类。WHERE 1=1:这是一个小技巧,用于避免在第一个条件前出现AND或OR关键字,导致 SQL 语法错误。 如果第一个<if>标签的条件成立,则会添加AND关键字,否则不会添加。<if test="username != null and username != ''">:如果username不为null且不为空字符串,则添加AND username LIKE #{username}到 SQL 语句中。<if test="email != null and email != ''">:如果email不为null且不为空字符串,则添加AND email = #{email}到 SQL 语句中。#{username}和#{email}:是 MyBatis 的参数占位符,用于将参数值安全地替换到 SQL 语句中。
Java 代码示例:
Map<String, Object> params = new HashMap<>();
params.put("username", "%john%");
params.put("email", "john.doe@example.com");List<User> users = sqlSession.selectList("findUsersByCondition", params);
生成的 SQL 语句示例:
如果 username 和 email 都不为空,则生成的 SQL 语句如下:
SELECT * FROM users
WHERE 1=1
AND username LIKE '%john%'
AND email = 'john.doe@example.com'
如果只有 username 不为空,则生成的 SQL 语句如下:
SELECT * FROM users
WHERE 1=1
AND username LIKE '%john%'
2、 choose、when、otherwise 标签
<choose> 标签类似于 Java 中的 switch 语句,用于多条件选择。 它包含多个 <when> 标签和一个 <otherwise> 标签。 MyBatis 会按照顺序评估每个 <when> 标签的 test 属性,如果有一个 <when> 标签的 test 属性为 true,则执行该 <when> 标签内的 SQL 片段,并跳过其他的 <when> 和 <otherwise> 标签。 如果所有的 <when> 标签的 test 属性都为 false,则执行 <otherwise> 标签内的 SQL 片段。
<select id="findUsersByCondition" parameterType="map" resultType="User">SELECT * FROM usersWHERE<choose><when test="username != null and username != ''">username LIKE #{username}</when><when test="email != null and email != ''">email = #{email}</when><otherwise>1=1 <!-- 如果没有条件,则查询所有用户 --></otherwise></choose>
</select>
解释:
<choose>:定义一个多条件选择结构。<when test="username != null and username != ''">:如果username不为null且不为空字符串,则添加username LIKE #{username}到 SQL 语句中。<when test="email != null and email != ''">:如果email不为null且不为空字符串,则添加email = #{email}到 SQL 语句中。<otherwise>:如果username和email都为空,则添加1=1到 SQL 语句中,表示查询所有用户。
Java 代码示例:
Map<String, Object> params = new HashMap<>();
// params.put("username", "%john%"); // 只设置 username
// params.put("email", "john.doe@example.com"); // 只设置 emailList<User> users = sqlSession.selectList("findUsersByCondition", params);
生成的 SQL 语句示例:
如果 username 不为空,则生成的 SQL 语句如下:
SELECT * FROM users
WHERE
username LIKE '%john%'
如果 email 不为空,则生成的 SQL 语句如下:
SELECT * FROM users
WHERE
email = 'john.doe@example.com'
如果 username 和 email 都为空,则生成的 SQL 语句如下:
SELECT * FROM users
WHERE
1=1
3、 where 标签
<where> 标签用于智能地添加 WHERE 子句。 它会自动判断是否需要添加 WHERE 关键字,并自动去除多余的 AND 或 OR 关键字。
<select id="findUsersByCondition" parameterType="map" resultType="User">SELECT * FROM users<where><if test="username != null and username != ''">username LIKE #{username}</if><if test="email != null and email != ''">AND email = #{email}</if></where>
</select>
解释:
<where>:智能地添加WHERE子句。- 如果至少有一个
<if>标签的条件成立,则<where>标签会自动添加WHERE关键字,并去除第一个AND关键字。 - 如果所有的
<if>标签的条件都不成立,则<where>标签不会添加任何内容。
Java 代码示例:
Map<String, Object> params = new HashMap<>();
params.put("username", "%john%");
params.put("email", "john.doe@example.com");List<User> users = sqlSession.selectList("findUsersByCondition", params);
生成的 SQL 语句示例:
如果 username 和 email 都不为空,则生成的 SQL 语句如下:
SELECT * FROM users
WHERE username LIKE '%john%'
AND email = 'john.doe@example.com'
如果只有 username 不为空,则生成的 SQL 语句如下:
SELECT * FROM users
WHERE username LIKE '%john%'
如果 username 和 email 都为空,则生成的 SQL 语句如下:
SELECT * FROM users
4、 set 标签
<set> 标签用于智能地添加 SET 子句。 它会自动判断是否需要添加 SET 关键字,并自动去除最后一个逗号。 通常用于 UPDATE 语句中。
<update id="updateUser" parameterType="User">UPDATE users<set><if test="username != null and username != ''">username = #{username},</if><if test="email != null and email != ''">email = #{email},</if></set>WHERE id = #{id}
</update>
解释:
<set>:智能地添加SET子句。- 如果至少有一个
<if>标签的条件成立,则<set>标签会自动添加SET关键字,并去除最后一个逗号。 - 如果所有的
<if>标签的条件都不成立,则<set>标签不会添加任何内容。
Java 代码示例:
User user = new User();
user.setId(1);
user.setUsername("new_username");
// user.setEmail("new_email@example.com"); // 不更新 emailsqlSession.update("updateUser", user);
生成的 SQL 语句示例:
如果 username 不为空,则生成的 SQL 语句如下:
UPDATE users
SET username = 'new_username'
WHERE id = 1
如果 username 和 email 都不为空,则生成的 SQL 语句如下:
UPDATE users
SET username = 'new_username',
email = 'new_email@example.com'
WHERE id = 1
5、 foreach 标签
<foreach> 标签用于循环遍历集合。 它可以用于构建 IN 子句、批量插入等场景。
<select id="findUsersByIds" parameterType="list" resultType="User">SELECT * FROM usersWHERE id IN<foreach item="id" collection="list" open="(" separator="," close=")">#{id}</foreach>
</select>
解释:
item="id":指定集合中的每个元素的名字为id。collection="list":指定要遍历的集合的名字为list。 如果参数是数组,则collection属性的值为array。open="(":指定循环开始时的字符串为(。separator=",":指定每个元素之间的分隔符为,。close=")":指定循环结束时的字符串为)。#{id}:表示集合中的每个元素的值。
Java 代码示例:
List<Integer> ids = Arrays.asList(1, 2, 3);List<User> users = sqlSession.selectList("findUsersByIds", ids);
生成的 SQL 语句示例:
SELECT * FROM users
WHERE id IN (1,2,3)
批量插入示例:
<insert id="insertUsers" parameterType="list">INSERT INTO users (username, email) VALUES<foreach item="user" collection="list" separator=",">(#{user.username}, #{user.email})</foreach>
</insert>
Java 代码示例:
List<User> users = new ArrayList<>();
users.add(new User("john", "john@example.com"));
users.add(new User("jane", "jane@example.com"));sqlSession.insert("insertUsers", users);
生成的 SQL 语句示例:
INSERT INTO users (username, email) VALUES
('john', 'john@example.com'),
('jane', 'jane@example.com')
6、 sql、include 标签
<sql> 标签用于定义 SQL 片段,<include> 标签用于引用 SQL 片段。 这可以提高代码的复用性。 ♻️
<sql id="userColumns">id, username, email
</sql><select id="findAllUsers" resultType="User">SELECT <include refid="userColumns"/> FROM users
</select><select id="findUserById" parameterType="int" resultType="User">SELECT <include refid="userColumns"/> FROM users WHERE id = #{id}
</select>
解释:
<sql id="userColumns">:定义一个名为userColumns的 SQL 片段,包含id, username, email。<include refid="userColumns"/>:引用名为userColumns的 SQL 片段。
生成的 SQL 语句示例:
findAllUsers 生成的 SQL 语句:
SELECT id, username, email FROM users
findUserById 生成的 SQL 语句:
SELECT id, username, email FROM users WHERE id = 1
五、 总结
MyBatis 的动态 SQL 功能非常强大,可以根据不同的条件生成不同的 SQL 语句,从而满足不同的查询需求。 掌握这些标签的用法,可以编写更灵活、可维护的 SQL 映射。 🎉
一些建议:
- 避免过度使用动态 SQL: 动态 SQL 虽然强大,但过度使用会增加代码的复杂性。 只有在必要的时候才使用动态 SQL。
- 注意 SQL 注入: 在使用动态 SQL 时,要注意 SQL 注入的风险。 使用 MyBatis 的参数占位符
#{}可以有效地防止 SQL 注入。 - 测试: 编写充分的测试用例,确保动态 SQL 的正确性。 ✅
希望这篇文章能够帮助你理解 MyBatis 的动态 SQL。 😊