目录
前言:
一、动态SQL_<if><where>
二、动态SQL_<set>
三、动态SQL_<choose><when><otherwise>
四、动态SQL_<foreach> 遍历Array数组进行批量删除
五、动态SQL_ <foreach>遍历Collection集合进行批量插入
六、动态SQL_ <foreach>遍历Collection集合进行批量插入
前言:
一个查询的方法的 Sql 语句不一定是固定的。比如电商网站的查询商品,用户使用不同条件查询,Sql 语句就会添加不同的查询条件。此时就需要在方法中使用动态Sql 语句。
一、动态SQL_<if><where>
介绍:
<if> 标签内的 Sql 片段在满足条件后才会添加,用法为: <if test="条件"> 。
<where> 可以代替 sql 中的 where 1=1 和第一个 and ,更符合程序员的开发习惯
1.持久层接口查询方法
//测试MyBatis动态sql语句标签如:<if>、where、set、when、choose、otherwise、foreach
public interface UserMapper2 {
// 1.查询满足条件的所有数据,测试动态SQL的<if>标签
// 用途:测试<if><where>标签
List<User> findByCondition(User user);
}
2.映射文件
<!--注意:这里的resultType、parameterType传入的是别名,在SqlMapConfig.xml中设置了-->
<!--1.查询满足条件的所有数据,测试动态SQL的<if>标签-->
<!--(1)where 1=1 条件是为了满足后面第一条if条件中的and,因为查询中第一个条件可能不符合,
但不能影响后面的条件,所以把where 1=1作为第一个条件 如:
select * from user where 1=1 <if></if>.....-->
<!-- (2)<where>标签可以代替where 1=1 并且可以省去第一个条件中的and-->
<!--(3)注意:username那里的模糊查询不能用'%${value}%',因为${}是字符串替换,用在普通类型的,而这里的参数类型为POJO类型-->
<select id="findByCondition" resultType="User" parameterType="string">
select * from user
<where>
<if test="username != null and username.length() != 0">
username like #{username}
</if>
<if test="sex != null and sex.length() != 0">
and sex = #{sex}
</if>
<if test="address != null and address.length() != 0">
and address = #{address}
</if>
</where>
</select>
3.测试方法
@Test
public void testFindByCondition(){
User user = new User();
//第一次查询,user对象是一个null对象,所以传入到sql中没有条件,调用where 1=1 查询所有数据
List<User> users1 = userMapper2.findByCondition(user);
users1.forEach(System.out::println);
user.setUsername("%尚学堂%");
//第二次查询,user对象有了”username=尚学堂“的值,传入username的条件并查询满足username=尚学堂的条件
List<User> users2 = userMapper2.findByCondition(user);
users2.forEach(System.out::println);
user.setAddress("北京");
//第三次查询,user对象有了”username=尚学堂、address=北京“的值,传入username、address的条件并查询满足条件的数据
List<User> users3 = userMapper2.findByCondition(user);
users3.forEach(System.out::println);
}
4.注意:
(1)if 中的条件不能使用 &&/|| ,而应该使用 and/or
2
(2)if 中的条件可以直接通过属性名获取参数 POJO 的属性值,并且该值可以调用方法。
3
(3)where 后为什么要加 1=1 ?
任意条件都可能拼接到Sql 中。如果有多个条件,从第二个条件开始前都需要加And 关键字。加上 1=1 这个永久成立的条件,就不需要考虑后面的条件哪个是第一个条件,后面的条件前都加And 关键字即可。
5.知识点整理:
(1)MyBatis的<if>标签使用“test”属性添加条件
(2)MyBatis的<if>中,多个条件同时满足需要用“and”连接,不能用&&
(3)MyBatis映射文件中,<where>的作用是“代替sql中where 1=1 和第一个and”
二、动态SQL_<set>
介绍:
<set> 标签用在update语句中。借助 <if> ,可以只对有具体值的字段进行更新。 <set> 会自动添加set关键字,并去掉最后一个if语句中多余的逗号。
1.持久层接口更新方法
// 2.动态更新数据,按给定的id主键值进行动态修改数据,可以只更新一行数据中的其中一个字段值,测试动态SQL的<set>标签 // 用途:测试<set>标签 void updateUser(User user);
2.映射文件
<!--2.动态更新数据,可以只更新一行数据中的其中一个字段值,测试动态SQL的<set>标签-->
<!--<set>标签可以代替set(update user (set)<set>...)和最后一个条件后的逗号,
如果没有<set>标签的话,最后一个if条件中要写上逗号(即address = #{address},)-->
<update id="updateUser" parameterType="User">
update user
<set>
<if test="username != null and username.length() !=0">
username = #{username},
</if>
<if test="sex != null and sex.length() !=0">
sex = #{sex},
</if>
<if test="address != null and address.length() !=0">
address = #{address}
</if>
</set>
<where>
id = #{id}
</where>
</update>
3.测试方法
@Test
public void testUpdateUser(){
User user = new User();
user.setId(2);
user.setUsername("我是程序员");
userMapper2.updateUser(user);
// 增删改操作记得要手动提交事务
session.commit();
}
4.知识点整理:
(1)MyBatis映射文件中,<set>的作用是“代替set关键字,并去掉最后一个if语句中多余的逗号”
三、动态SQL_<choose>、<when>、<otherwise>
介绍:
这些标签表示多条件分支,类似 JAVA 中的 switch...case 。 <choose> 类似
switch , <when> 类似 case , <otherwise> 类似 default ,用法如下:
1.持久层接口查询方法
// 3.查询满足条件的所有数据,测试动态SQL的<choose><when><otherwise>标签
// 按给定的内容进行模糊查询(内容小于5)或精确查询(内容小于10),否则返回id=1的数据(内容大于10)
// 用途:测试<choose><when><otherwise>标签,一般三个连着使用,相当于java中的Switch-case-default
List<User> findByUsername(String username);
2.映射文件
<!--3.查询满足条件的所有数据,测试动态SQL的<choose><when><otherwise>标签-->
<!--<choose><when><otherwise>相当于java的选择条件句,
<choose>相当于Switch
<when> 相当于case
<otherwise> 相当于default-->
<select id="findByUsername" parameterType="string" resultType="User">
select * from user
<where>
<choose>
<when test="username.length() < 5">
<bind name="username" value="'%'+username+'%'"/>
username like #{username}
</when>
<when test="username.length() < 10">
username = #{username}
</when>
<otherwise>
id = 1
</otherwise>
</choose>
</where>
</select>
这段代码的含义为:用户名 <5 时使用模糊查询,用户名 >=5 并且<10时使用精确查询,否则查询 id 为 1 的用户
3.测试方法
@Test
public void testFindByUsername(){
// 精确查询username属性中含有北京的数据
List<User> user = userMapper2.findByUsername("北京");
user.forEach(System.out::println);
}
4.知识点整理:
1.MyBatis 映射文件中, <choose> 的作用为“表示多条件分支”
2. 在 MyBatis 映射文件中 , <when> 需要被嵌套“ <choose> ”
四、动态SQL_<foreach> 遍历Array数组进行批量删除
介绍:
<foreach> 类似JAVA中的for循环,可以遍历集合或数组。 <foreach> 有如下属性:
collection :遍历的对象类型
open :表示该语句以什么开始,常用 “(”;
close : 表示以什么结束,常用 “)”。
separator :表示在每次进行迭代之间以什么符号作为分隔符,常用 “,”;
item :表示集合中每一个元素进行迭代时的别名,随便起的变量名,遍历 map 时表示键值对的值。
index :遍历 List 、数组时表示遍历的索引位置,遍历 map 时表示键值对的键。
遍历数组:
我们使用 <foreach> 遍历数组进行批量删除。
1.持久层接口删除方法
// 4.批量删除指定id的一些数据,测试动态SQL的<foreach>标签,遍历Array // 按给定的id值进行批量删除数据,传入一个数组,数组中包含要删掉的id值 // 系统的删除语句:delete from user where id in(12,13,14,16,17,18) // 用途:测试<foreach>标签,遍历Array数组 void deleteBatch(int[] ids);
2.映射文件
<!--4.批量删除指定id的一些数据,测试动态SQL的<foreach>标签,遍历Array-->
<!-- collection:遍历的对象类型
open:开始的sql语句
close:结束的sql语句
separator:遍历每项间的分隔符(自定义分隔符形式形式,如逗号、、、)
item(名字自定义):表示本次遍历获取的元素,遍历List、Set、Array时表示每项元素,遍历Map时表示键值对的值
index:遍历List、Array时表示遍历的索引,遍历Map时表示键值对的键-->
<delete id="deleteBatch" parameterType="int">
delete from user
<where>
<foreach collection="array" open="id IN(" close= ")" separator="," item="id">
#{id}
</foreach>
</where>
</delete>
3.测试方法
@Test
public void testDeleteBatch(){
int[] ids = {12,13,14,16,17,18};
userMapper2.deleteBatch(ids);
session.commit();
}
4.知识点整理:
1. MyBatis 的 <foreach> 中,使用属性表示遍历的数据类型" item "
2. 在 MyBatis 映射文件中,遍历数组时需要将 collection 的值设为"array"
五、动态SQL_<foreach> 遍历Collection集合进行批量插入
介绍:
<foreach>
遍历
List
和
Set
的方法是一样的,这里使用
<foreach>
遍历
List集合
进
行批量添加
1.持久层接口插入方法
// 5.批量插入数据,测试动态SQL的<foreach>标签,遍历Collection
// 系统插入语句:insert into user(username,sex,address) values(),(),()
// 批量新增方法,测试<foreach>标签,遍历Collection集合
void insertBatch(List<User> user);
2.映射文件
<!--5.批量插入数据,测试动态SQL的<foreach>标签,遍历Collection-->
<!--Collection:遍历的对象类型 item:遍历获取的元素(名字自定义,可以调用字段名进行传参) separator:分隔符-->
<insert id="insertBatch" parameterType="User">
insert into user(username,sex,address) values
<foreach collection="list" item="user" separator=",">
(#{user.username},#{user.sex},#{user.adddress})
</foreach>
</insert>
3.测试方法
@Test
public void testInsertBatch(){
User user1 = new User("程序员1","男","深圳");
User user2 = new User("程序员2","女","上海");
List<User> users = new ArrayList();
users.add(user1);
users.add(user2);
// 批量插入
userMapper2.insertBatch(users);
session.commit();
}
4.知识点整理:
(1)在MyBatis中映射文件中,遍历List时<foreach>的item属性表示“遍历的每项元素”
(2)在MyBatis的<foreach>标签中,使用属性遍历每项间的分隔符“separator”
六、动态SQL_<foreach> 遍历Collection集合进行批量插入
介绍:
使用 <foreach>标签 遍历Map进行多条件查询。
1.持久层接口查询方法
// 6.多条件查询:批量查询方法,测试<foreach>标签,遍历Map集合
/**
* 多条件查询:批量查询方法,测试<foreach>标签,遍历Map集合
* @param map 查询的条件键值对 键:属性名 值:出入要查询的属性名
* 系统的查询语句:select * from user where username = ? and sex = ?
* @return
* @Param:为参数起别名
*/
List<User> findUser(@Param("queryMap") Map<String,Object> map);
2.映射文件
<!--6.多条件查询:批量查询方法,测试<foreach>标签,遍历Map集合-->
<!--注意:1.collection:传入的不是遍历的对象类型,List、Set、Array传入的类型分别是list、set、array,
但Map集合传入的不是map,而是持久层接口中定义的参数名 如:@Param("queryMap")
2.separator:传入的是and不是逗号,因为查询给定的条件是and连接,修改是逗号连接
3.index:Map类型的键,起名为key item:Map类型的值,起名为value
4.特别注意:sql语句key=value(键=值),键只能用${},作为字符串拼接到sql语句中,因为键是属性名
值可以用#{},作为占位符-->
<select id="findUser" parameterType="map" resultType="User">
select * from user
<where>
<foreach collection="queryMap" separator="and" index="key" item="value">
${key} = #{value}
</foreach>
</where>
</select>
3.测试方法
@Test
public void testFindUser(){
Map<String,Object> queryMap = new HashMap();
queryMap.put("sex","男");
queryMap.put("address","北京");
List<User> users = userMapper2.findUser(queryMap);
users.forEach(System.out::println);
}
4.知识点整理:
(1)MyBatis 的 <foreach> 中,遍历 Map 时 index 属性表示“键值对的键”
(2) MyBatis 的 <foreach> 中,遍历 Map 时 item 属性表示“键值对的值”