目录
- 一、 什么是动态 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。 😊