文章目录
- 一、简介
- 二、if标签
- 2.1 if标签的简单使用
- 2.2 where标签
- 2.3 trim标签(了解)
- 三、choose标签 & set标签
- 3.1 choose标签
- 3.2 set标签
- 四、foreach标签
- 4.1 foreach标签的简单使用
- 4.2 批量插入
- 五、内置参数
- 六、bind标签
- 七、sql标签 & include标签
学习地址🔗
- https://www.bilibili.com/video/BV1mW411M737
- https://www.bilibili.com/video/BV1NE411Q7Nx
- 官网文档
一、简介
💬概述:动态SQL——Dynamic SQL,是MyBatis中强大功能之一,可以根据不同条件来拼接SQL语句
🔑实现动态SQL的几个重要标签
- if
- choose(when、otherwise)
- trim(where、set)
- foreach
🔑关于动态SQL中使用到的表达式语言——OGNL
-
全称:Object Graph Navigation Language,对象图导航语言
-
概述:一种强大的表达式语言,使用它可以方便地操作对象属性,类似于EL表达式
-
使用
作用 表达式 访问对象属性 person.name 调用方法 person.getName() 调用静态属性 @java.lang.Math@PI 调用静态方法 @java.util.UUID@randomUUID 调用构造方法 new com.key.mybatis.entity.Person(“Key”).name 算术运算符 +,-,*,/,%等 逻辑运算符 in,not in,and,or,<,>,=,<=,>=,!=,==等 拼接字符串 ‘str1’ + ‘str2’ 💡 在xml文件中,某些敏感字符需要使用其转移字符代替,如逻辑运算符中
<
、>
等
二、if标签
2.1 if标签的简单使用
💬概述:在SQL映射文件的SQL标签中,可以添加<if>
子标签,根据设置的条件动态拼接SQL语句
🔑作用:根据设置的条件动态直接拼接SQL语句,不进行修剪,一般用于动态拼接WHERE
子句的查询条件
🔑属性——text
(必须设置)
- 作用:使用OGNL表达式来设置条件
- 属性值:OGNL表达式
🔑使用:直接在SQL语句标签内添加<if>
,并添加text
属性设置条件,<if>
标签体内添加动态的语句,当满足text
中设置的条件时才会拼上该语句
<!-- id不为null时使用id查询用户信息 -->
<if text="userid != null">
`user_id` = #{userid}
</if>
💡
text
的属性值(OGNL表达式)中的userid
对应#{Key}
中的键Key,即获取参数时的键,需要根据键获取参数值后再来判断是否为null,不是数据库表中的字段名user_id
🔑测试:使用不为null的参数(字段)来查询对应用户信息
-
分析:在书写SQL语句时,不能直接知道传进来的参数值哪一个为null,所以需要对查询的条件进行动态拼接
-
用户持久层接口中添加对应方法
// 根据if标签的条件来查询用户信息 List<User> getUsersByIfCondition(User user);
-
用户映射文件
<!-- 根据if标签条件查询 --> <select id="getUsersByIfCondition" resultType="com.key.mybatis.entity.User"> select * from `user` where <!-- 使用if标签动态拼接查询条件 --> <!-- id不为null,用id查询 --> <if test="userid != null"> `user_id` = #{userid} </if> <!-- 姓名不为null,用姓名查询 --> <if test="username != null and username.trim() != ''"> and `user_name` = #{username} </if> <!-- 密码不为null,用密码查询 --> <if test="password != null"> and `password` = #{password}; </if> </select>
💡 因为持久层接口的对应方法中形参为
User
,即POJO,所以在映射文件中可以直接将User
类的属性名作为键Key获取参数值 -
测试方法1.0——只有用户id不为null,则只根据用户id查询
-
方法
// 创建一个用户对象,只有用户id不为null User user = new User(2, null, null); // 调用持久层接口方法 List<User> users = mapper.getUsersByIfCondition(user); users.forEach(System.out :: println);
-
打印结果
-
-
测试方法2.0——用户姓名为null,id和密码不为null,则根据id和密码来查询
-
方法
// 创建一个用户对象,用户姓名为null,id和密码不为null User user = new User(2, null, "12444"); // 调用持久层接口方法 List<User> users = mapper.getUsersByIfCondition(user); users.forEach(System.out :: println);
-
打印结果
-
-
测试方法3.0——用户id和密码都为null,只有姓名不为null,根据姓名查询
-
方法
// 创建一个用户对象,用户id和密码都为null,只有姓名不为null User user = new User(null, "周慧敏", null); // 调用持久层接口方法 List<User> users = mapper.getUsersByIfCondition(user); users.forEach(System.out :: println);
-
打印结果
-
❌报错原因分析:
① 在id为null且姓名不为null情况下,判断id是否为null的
<if>
标签体内的查询条件(user_id = #{userid}
)就不会拼接到SQL语句中,姓名对应的<if>
标签体内容会完整拼接到SQL语句中② 姓名对应的
<if>
标签体内容是and user_nam = #{username}
,查询条件前面还多了个and
,而它前面已经没有其他查询条件可以拼接,因此最终拼接而成的SQL语句中,where
和查询条件之间也会多一个and
,该SQL语句很明显不合法,因此报错🔺 解决方法
① 在每一个
<if>
标签体内的查询条件前面都加上and
,然后在where
子句后加上一个1=1
的条件,这样就能保证where
子句后面拼上的是条件1=1
,而不是多余的and
,而且条件1=1
恒成立,不会对后面通过and
拼起来的查询条件有任何影响,但这种方法仅适用于通过与and
连接的查询条件
② 使用<where>
标签👇
-
2.2 where标签
❓ 问题引入:在上面对
<if>
标签的测试方法3.0中,遇到拼接后的SQL语句不合法的问题,如果只使用<if>
标签动态拼接SQL语句中的查询条件,就很难避免这个问题,因此需要使用<where>
标签来解决(MyBatis推荐)
💬概述:<where>
也是<select>
标签的子标签,它能代替查询SQL语句的where
子句
🔑作用:代替where
子句,将查询条件作为其标签体内容,使查询条件也能动态拼接,即将合法的查询条件前面多余的内容去掉,剩下合法、有用的内容拼接到where
子句后
🔑使用限制:<where>
只能去掉查询条件前面多余的内容,如果多余的内容在合法查询条件的后面,则无法去掉
🔑测试1.0:传入的用户id和密码都为null,只有姓名不为null,则根据姓名查询用于信息(上面的测试3.0)
-
dao方法不变
List<User> getUsersByIfCondition(User user);
-
用户映射文件
<!-- 根据if标签条件查询 --> <select id="getUsersByIfCondition" resultType="com.key.mybatis.entity.User"> select * from `user` <!-- 使用where标签代替where子句 - where标签代替了where子句,因此where就不用再添加 - if标签放在where标签里面 --> <where> <!-- id不为null,用id查询 --> <if test="userid != null"> `user_id` = #{userid} </if> <!-- 姓名不为null,用姓名查询 --> <if test="username != null and username.trim() != ''"> and `user_name` = #{username} </if> <!-- 密码不为null,用密码查询 --> <if test="password != null"> and `password` = #{password}; </if> </where> </select>
-
测试方法
// 创建一个用户对象,姓名为null User user = new User(null, "周星驰", null); // 调用持久层接口方法 List<User> users = mapper.getUsersByIfCondition(user); users.forEach(System.out :: println);
-
打印结果
🔑测试2.0:修改<if>
标签中查询内容的书写,将and
放在合法的查询条件后面
-
dao方法与测试方法与上面👆一样
-
映射文件中
<!-- 根据if标签条件查询 --> <select id="getUsersByIfCondition" resultType="com.key.mybatis.entity.User"> select * from `user` <!-- 使用where标签代替where子句 --> <where> <!-- * 注意这里的查询条件中,将'and'放到后面 --> <!-- id不为null,用id查询 --> <if test="userid != null"> `user_id` = #{userid} and </if> <!-- 姓名不为null,用姓名查询 --> <if test="username != null and username.trim() != ''"> `user_name` = #{username} and </if> <!-- 密码不为null,用密码查询 --> <if test="password != null"> `password` = #{password}; </if> </where> </select>
-
打印结果
-
分析结果:有打印结果可知,
<where>
标签不会将合法的查询条件后面多余的内容去掉,只能去掉前面的,因此最终拼接而成的SQL语句后面还是会有一个多余的and
,这也是不合法的SQL语句,因此也报错
2.3 trim标签(了解)
❓ 问题引入:在上面的测试2.0中,可以看到
<where>
使用限制——查询条件中多余的内容只能放在前面,如果放在后面就无法去掉,因此最终得到的SQL语句仍然是不合法的,此时可以使用<trim>
标签解决
💬概述:<trim>
也是SQL语句标签的子标签,与<where>
标签使用类似
🔑作用:trim是修剪的意思,也是将查询条件作为其标签体内容,对查询条件中的前缀后缀内容进行修改后再拼接到最终的SQL语句中,因此合法查询条件的前面和后面的多余内容都能去掉
🔑 <trim>
中四个属性
属性名 | 作用 |
---|---|
prefix | 指定拼接后查询条件的前缀 |
suffix | 指定拼接后查询条件的后缀 |
prefixOverrides | 指定需要覆盖(去掉)的拼接后查询条件的前缀 |
suffixOverrides | 指定需要去掉的拼接后查询条件的后缀 |
💡 这里的“拼接后查询条件”是指直接拼接而成、没有被修饰过的拼接结果,可能会带有多余的前缀和后缀
🔑测试:将<if>
标签中的and
放在合法的查询条件后面,作为后缀,且不添加where
子句和<where>
标签(在<where>
标签测试2.0基础上修改)
-
dao方法和测试方法都与上面👆一样
-
映射文件
<!-- 根据if标签条件查询 --> <select id="getUsersByIfCondition" resultType="com.key.mybatis.entity.User"> select * from `user` <!-- 使用trim标签,修改查询条件的前后缀 - prefix="where":表示在拼接后的查询结果前加上 where - suffixOverrides="and":表示去掉拼接后的查询条件后面的 and --> <trim prefix="where" suffixOverrides="and"> <!-- id不为null,用id查询 --> <if test="userid != null"> `user_id` = #{userid} and </if> <!-- 姓名不为null,用姓名查询 --> <if test="username != null and username.trim() != ''"> `user_name` = #{username} and </if> <!-- 密码不为null,用密码查询 --> <if test="password != null"> `password` = #{password}; </if> </trim> </select>
-
打印结果
三、choose标签 & set标签
3.1 choose标签
💬概述:<choose>
标签也是SQL语句标签的子标签,表示分支选择的意思,与switch...case
使用类似
🔑作用:选择出符合指定条件的唯一内容,即只选择出一种情况
🔑子标签:<choose>
标签中无属性,但有两个重要的子标签
子标签名 | 属性 | 解释 | 是否必须添加 |
---|---|---|---|
when | text:使用OGNL表达式指定选择的条件 | 指定选择的条件,标签体为选择的内容;类似于case ;MyBatis会根据<when> 标签的添加顺序来匹配条件,一旦有一个满足条件,就不会再匹配后面的<when> 标签条件 | 是 |
otherwise | 无 | 指定默认选择的内容,当所有<when> 中指定条件都不满足时就选择<otherwise> 标签体中的内容,类似于default | 否 |
🔑使用:直接在SQL语句标签中添加<choose>
子标签,然后在<choose>
中再添加<when>
标签指定选择的条件,根据需要添加<otherwise>
标签指定默认选择
<!-- 使用choose根据条件选择其中一种情况 -->
<choose>
<when test="userid != null">
`user_id` = #{userid}
</when>
<when test="username != null">
`user_name` like #{username}
</when>
<!-- 默认选择,如果when条件都不满足,就查询全部信息 -->
<otherwise>
1=1
</otherwise>
</choose>
💡 因为
<choose>
标签只会选择出一种情况,因此每一个<when>
标签体内的查询条件中不用添加连接词(and
、or
)
🔑测试:查询用户信息,如果id不为null就只用id查询,如果id为null就只用姓名模糊查询,如果姓名也为空就只用密码查询,如果都为null,则就直接将所有用户信息查出
-
用户dao接口方法
List<User> getUsersByChooseCondition(User user);
-
用户映射文件
<!-- 根据choose标签查询 --> <select id="getUsersByChooseCondition" resultType="com.key.mybatis.entity.User"> select * from `user` <!-- 以后都写where标签 --> <where> <!-- 使用choose根据条件选择其中一种情况 --> <choose> <when test="userid != null"> `user_id` = #{userid} </when> <!-- 姓名是模糊查询,用like关键字 --> <when test="username != null and username.trim() != ''"> `user_name` like #{username} </when> <when test="password != null"> `password` = #{password} </when> <!-- 默认选择,如果when条件都不满足,就查询全部信息 --> <otherwise> 1=1 </otherwise> </choose> </where> </select>
-
测试方法:id为null,用户姓名带有‘周’字,密码11baa
@Test public void testChooseCondition() { // 获取SqlSession SqlSession sqlSession = MyBatisUtil.getSqlSession(); // 获取mapper对象 UserDao mapper = sqlSession.getMapper(UserDao.class); // 创建一个用户对象,id为null,用户姓名带有‘周’字,密码11baa User user = new User(null, "%周%", "11baa"); // 调用dao方法 List<User> users = mapper.getUsersByChooseCondition(user); users.forEach(System.out :: println); // 关闭sqlSession sqlSession.close(); }
-
打印结果
🔺 结果分析:由打印结果可以看出,最终拼出的SQL语句中只有根据姓名模糊查询的条件,即使传入的参数中密码’password’也不为null,但密码对应的
<when>
选择条件在姓名后面,因此就不会去匹配密码对应的<when>
选择条件
3.2 set标签
💬概述:<set>
标签是<update>
标签中的子标签,用于代替更新SQL语句中的set
子句
🔑作用:代替更新语句中的set
子句,选择性拼接set
后面的更新内容,可以去掉拼接后的多余内容,一般是,
🔑使用:在<update>
标签中添加<set>
标签,代替set
子句,同时使用<if>
根据指定条件动态获取更新内容
<!-- 使用set标签动态拼接更新内容 -->
<set>
<!-- 使用if标签动态获取更新内容 -->
<if test="username != null">
`user_name` = #{username},
</if>
<if test="password != null">
`password` = #{password}
</if>
</set>
❓ 关于去掉拼接后的多余内容
- 如果更新语句中不使用
<set>
标签,而是直接使用set
子句和<if>
标签动态拼接更新内容,则最终拼接的SQL语句有可能在后面多了个,
,造成SQL语句不合法。与<where>
解决的情况类似- 对于去掉多余的拼接内容,一样能使用
<trim>
标签来实现,此时需要添加的前缀prefix="set"
,需要去掉的后缀suffixOverrides=","
(不推荐使用)
🔑测试:修改id为5的用户信息,只修改不为null的字段信息
-
用户dao接口方法
int updateUserBySetCondition(User user);
-
用户映射文件
<!-- 使用set标签更新用户信息 --> <update id="updateUserBySetCondition"> update `user` <!-- 使用set标签动态拼接更新内容 --> <set> <!-- 使用if标签动态获取更新内容 --> <if test="username != null"> `user_name` = #{username}, </if> <if test="password != null"> `password` = #{password} </if> </set> <!-- 最后还有查询条件的拼接,使用where --> <where> `user_id` = #{userid} </where> </update>
-
测试方法
@Test public void testSetCondition() { // 获取SQlSession SqlSession sqlSession = MyBatisUtil.getSqlSession(); // 获取mapper UserDao mapper = sqlSession.getMapper(UserDao.class); // 创建一个用户对象 User user = new User(5, "周海媚", null); // 调用dao方法 int result = mapper.updateUserBySetCondition(user); if (result == 0) { System.out.println("更新失败!"); } else { System.out.println("更新成功!"); } // 提交事务 sqlSession.commit(); // 关闭sqlSession sqlSession.close(); }
-
打印结果
四、foreach标签
4.1 foreach标签的简单使用
💬概述:<foreach>
标签也是SQL语句标签的一个子标签,可以实现循环遍历的功能
🔑作用:循环遍历指定的数组或集合,并将遍历后的结果拼接到SQL语句中
🔑属性:<foreach>
有下列主要属性
属性名 | 属性值 | 解释 | 是否必须添加 |
---|---|---|---|
collection | 属性值为需要遍历的集合名称,对应dao接口方法集合类型形参 | 标识出<foreach> 中所遍历的集合或数组;如果在dao接口方法中没有为形参命名,则collection 属性值只能使用默认键——【argN、collection、list] | 是 |
item | 自定义的变量名 | 标识当前遍历的元素,通过该属性值能获取每一个元素以及每一个元素的属性 | 否 |
separator | 自定义的分隔符 | 为遍历的集合或数组的每一项之间添加一个分割符 | 否 |
open | 自定义字符 | 为循环结束后拼接的语句前面添加一个开始字符 | 否 |
close | 自定义字符 | 为循环结束后拼接的语句后面添加一个结束字符 | 否 |
index | 自定义的变量名 | ①如果遍历的是List 集合或数组,则该属性就是每一项的索引值;②如果遍历的是Map 集合,则该属性就是Map 中的键Key | 否 |
🔑使用
- 在SQL语句标签中添加
<foreach>
标签,<foreach>
标签内添加相关属性 - 使用
#{}
或${}
获取集合中每一项的值
<foreach collection="ids" item="uId" separator="," open="(" close=")">
#{uId}
</foreach>
🔑测试:查询id为1-4之间的用户信息
-
分析
- 查询不同id的用户信息,可以使用
in ()
语句来实现,而()
里面的各个id可以封装成一个id集合,然后再SQL语句中遍历出来即可 - dao接口方法中为形参命名,在映射文件取参数时就可以直接通过自定义名来获取
- 因为
()
里面的不同参数之间用,
隔开,因此在<foreach>
遍历时也需要使用separator
属性为每一项之间添加分隔符,
,不能在循环体中直接写,
,因为这样写会使遍历的最后一项后面也有一个,
,从而造成SQL语句不合法 - 因为要遍历的集合在
()
里面,即<foreach>
遍历结束后拼接的内容添加到()
里面,有两种实现方式
① 将左括号(
写在在<foreach>
前面,右括号)
写在后面,相当于用()
将<foreach>
包裹起来
② 使用<foreach>
标签中的open
和close
属性,为循环遍历结束后拼接的内容前面加上开始字符(
,后面加上结束字符)
(推荐)
- 查询不同id的用户信息,可以使用
-
用户dao接口方法
List<User> getUsersByForeachCondition(@Param("ids") List<Integer> ids);
-
用户映射文件
<!-- 根据指定的id集合查询出对应的用户信息 --> <select id="getUsersByForeachCondition" resultType="com.key.mybatis.entity.User"> select * from `user` <where> `user_id` in <foreach collection="ids" item="uId" separator="," open="(" close=")"> #{uId} </foreach> </where> </select>
-
测试方法
@Test public void testForeachCondition() { // 获取SqlSession SqlSession sqlSession = MyBatisUtil.getSqlSession(); // 获取mapper UserDao mapper = sqlSession.getMapper(UserDao.class); // 调用dao方法 List<User> users = mapper.getUsersByForeachCondition(Arrays.asList(1, 2, 3, 4)); users.forEach(System.out :: println); // 关闭sqlSession sqlSession.close(); }
💡 测试中直接使用工具类的方法创建id集合——
Arrays.asList()
-
打印结果
4.2 批量插入
💡 下面只针对MySQL数据库支持的批量插入方式
💬概述:使用<foreach>
标签还可以遍历多个对象记录,实现向数据库表中批量插入多条记录
🔑批量插入方式1.0——在插入SQL语句中的values
后添加多个()
,多个()
之间用,
分隔开
-
用户dao接口方法
int batchInsertUsersByForeach(@Param("users") List<User> users);
-
用户映射文件
<!-- 批量插入多条用户记录1.0 --> <insert id="batchInsertUsersByForeach"> insert into `user`(`user_name`, `password`) values <!-- 使用foreach循环遍历每一条插入数据 --> <foreach collection="users" item="u" separator=","> (#{u.username}, #{u.password}) </foreach> </insert>
💡 这里是将
()
写在<foreach>
标签体(循环体)中,因为要遍历的每一项包含了()
,而不是每一项在()
中 -
测试方法
@Test public void testBatchInsertByForeach() { // 获取SqlSession SqlSession sqlSession = MyBatisUtil.getSqlSession(); // 获取mapper UserDao mapper = sqlSession.getMapper(UserDao.class); // 创建一个用户集合 List<User> users = new ArrayList<>(); users.add(new User(null, "宋江", "song123")); users.add(new User(null, "武松", "wu123")); users.add(new User(null, "潘金莲", "pan123")); int result = mapper.batchInsertUsersByForeach(users); if (result == 0) { System.out.println("批量插入失败!"); } else { System.out.println("批量插入成功!"); } // 提交事务 sqlSession.commit(); // 关闭 sqlSession.close(); }
-
打印结果
🔑批量插入方式2.0——直接执行多次insert
语句,每条insert
语句之间用;
分隔开
-
用户dao接口方法同上
-
用户映射文件
<!-- 批量插入2.0 --> <insert id="batchInsertUsersByForeach"> <!-- 直接使用foreach遍历多次insert语句,每条语句之间用;隔开 --> <foreach collection="users" item="u" separator=";"> insert into `user`(`user_name`, `password`) values(#{u.username}, #{u.password}) </foreach> </insert>
-
在jdbc属性文件中添加
allowMultiQueries
参数,并设置为trueprop.url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
💡 此操作必不可少,因为参数
allowMultiQueries
默认为false,即MySQL默认不支持多条SQL语句通过;
分隔开并同时执行 -
测试方法
// 创建一个用户集合 List<User> users = new ArrayList<>(); users.add(new User(null, "吴用", "wu456")); users.add(new User(null, "武大郎", "da123")); users.add(new User(null, "扈三娘", "hu123")); int result = mapper.batchInsertUsersByForeach(users); if (result == 0) { System.out.println("批量插入失败!"); } else { System.out.println("批量插入成功!"); }
-
打印结果
五、内置参数
💬概述:MyBatis中不仅可以获取dao接口方法传递过来的参数值,还能使用内置参数来获取值,且在OGNL表达式中可以直接使用内置参数
🔑两个内置参数
-
_parameter
-
概述
① 如果dao接口只传入单个简单类型的形参,则
_parameter
就表示这个形参,可以直接根据它来获取对应参数值;② 如果形参中传入多个参数,MyBatis会将dao接口方法中的形参封装成一个Map
集合,而内置参数_parameter
就表示这个Map
集合 -
作用:表示任意传进来的单个参数或参数
Map
集合,可以直接获取对应参数值 -
使用:在
<if>
标签的text
属性中判断传入的形参是否为null,如果不为null才获取对应参数<!-- 直接根据内置参数_parameter判断传入形参是否为null --> <if text="_parameter != null"> where `user_id` = #{userid} </if>
-
使用细节
_parameter
一般使用在判断条件中(如果<if>
标签的text
属性里面),即OGNL表达式中,不使用在#{}
获取参数- 如果传入单个对象类型的形参,则可以直接使用
_parameter.属性名
来获取对象的属性值 - 如果传入多个形参,则可以使用
_parameter.键Key
的方式来获取对应参数值,包括默认键——argN和paramN - 如果传入单个普通类型参数,则可以直接使用
_parameter
就能获取到参数值,或者使用_parameter.键Key
-
-
_databaseId
-
概述:如果全局配置文件中设置了
<databaseIdProvider>
标签,并为各个数据库厂商标识设置了别名,则内置参数_databaseId
就表示当前环境下数据库厂商标识的别名 -
作用:可以直接在SQL语句标签体中获取当前环境的数据库厂商标识,并可以根据不同环境下的数据库厂商设置不同的SQL语句
-
使用:在
<if>
标签的text
属性中判断当前环境的数据库厂商,然后使用对应的SQL语句<!-- 根据数据库厂商标识的别名来选择查询数据库表 --> <if test="_databaseId == 'mysql'"> <!-- mysql下查询user表 --> select * from `user` </if> <if test="_databaseId == 'oracle'"> <!-- oracle下查询employeeb --> select * from `employee` </if>
-
六、bind标签
💬概述:<bind>
也是SQL语句标签的子标签,bind是绑定的意思,顾名思义就是用来绑定数据或值
🔑作用:使用<bind>
标签,可以为自定义的值绑定一个变量名,根据变量名就能获取到对应的值
🔑<bind>
标签的两个属性
属性名 | 属性值 | 解释 |
---|---|---|
name | 自定义的变量名 | 为自定义的新参数绑定一个变量名,SQL语句中通过#{Key} 获取参数值时,就可以直接将该变量名作为键Key来获取新的参数值 |
value | 自定义的新参数 | 在value 属性中可以使用OGNL表达式来自定义新的参数,比如可以直接根据键Key获取传进来的形参对应的参数值,然后将参数值修改成新的参数 |
🔑使用:根据姓名模糊查询用户信息,模糊查询时直接传入关键字,不传入通配符(%
或_
),在映射文件中再为传入的关键字添加上通配符,形成一个新参数,然后使用<bind>
为该新参数绑定一个变量名,SQL语句中根据该变量名来获取对应参数值
-
dao接口方法
List<User> listUsersByBind(String nameKey);
-
映射文件
<!-- 根据姓名关键字模糊查询 --> <select id="listUsersByBind" resultType="com.key.mybatis.entity.User"> <!-- 使用bind标签绑定新的参数 - name="newName":为自定义的新参数绑定一个变量名 - value="...":自定义新的参数,也是使用OGNL表达式 --> <bind name="newName" value="'%' + nameKey + '%'"/> select * from `user` where `user_name` like #{newName}; </select>
-
测试方法
@Test public void testBind() { // 获取SqlSession SqlSession sqlSession = MyBatisUtil.getSqlSession(); // 获取mapper UserDao mapper = sqlSession.getMapper(UserDao.class); List<User> users = mapper.listUsersByBind("周"); users.forEach(System.out :: println); // 关闭sqlSession sqlSession.close(); }
七、sql标签 & include标签
🔑sql标签
- 概述:
<sql>
标签是与其他SQL语句标签同级的标签,在<sql>
标签中也能书写SQL语句 - 作用:抽取可重用的SQL语句,一般用于抽取插入语句、更新语句时的数据库表的列名
- 使用细节:
<sql>
标签中也可以使用动态SQL语句中各种条件标签,如<if>
、<where>
等 - 属性——id:唯一标识,根据sql-id可以引用其抽取的SQL语句
🔑include标签
-
概述:
<include>
标签是SQL语句标签的子标签,与<sql>
标签是合作伙伴 -
作用:引用
<sql>
中抽取的可重用SQL语句 -
作用位置:穿插在SQL语句中,取代被抽取的部分SQL语句
-
使用细节:在
<include>
标签中还可以通过<property>
子标签自定义属性,<sql>
标签中就可以使用${}
获取对应属性💡
<sql>
标签中获取<include>
定义的属性时,只能使用${}
,不能使用#{}
-
属性——refid:对应
<sql>
标签中的唯一标识sql-id,根据该id标识了对应<sql>
标签后,<include>
所在的位置就会被<sql>
中抽取的SQL语句所代替,最终拼接成完整的SQL语句
🔑sql标签和include标签结合使用
-
使用1.0——使用
<sql>
抽取插入语句中的各个数据库表列名,然后在SQL语句标签中使用<include>
引用对应SQL<!-- 使用sql标签和include标签 --> <insert id="insertUserBySqlAndInclude"> insert into `user` ( <!-- include标签直接写在SQL语句中,取代抽取的SQL --> <include refid="insertColumn"/> ) values(#{userid}, #{username}, #{password}) </insert> <!-- 抽取可重用SQL语句 --> <sql id="insertColumn"> `user_name`, `password` </sql>
-
使用2.0——在
<include>
中为密码字段’password’再自定义一个名称,然后在<sql>
中使用自定义名来获取对应字段名<!-- 使用sql标签和include标签 --> <insert id="insertUserBySqlAndInclude"> insert into `user` ( <include refid="insertColumn"> <!-- 自定义属性 --> <property name="pwd" value="password"/> </include> ) values(#{userid}, #{username}, #{password}) </insert> <!-- 抽取可重用SQL语句 --> <sql id="insertColumn"> <!-- 使用${}获取include设置的属性值 --> `user_name`, ${pwd} </sql>