目录
前言
一、动态SQL---if标签
1. 持久层添加用户通用查询方法
2. 映射文件添加相关标签
3. 测试类新建测试方法
4. 运行结果
二、动态SQL---where标签
1. 映射文件添加相关标签
2. 测试类新建测试方法
3. 运行结果
三、动态SQL---set标签
1. 持久层添加用户更新方法
2. 映射文件添加相关标签
3. 测试类新建测试方法
4. 运行结果
四、动态SQL---choose和wen和otherwise标签
1. 持久层添加用户通用查询方法
2. 映射文件添加相关标签
3. 测试类新建测试方法
4. 运行结果
五、动态SQL---foreach标签
1. 遍历数组
(1)持久层添加用户批量删除方法
(2)映射文件添加相关标签
(3)测试类新建测试方法
(4)运行结果
2. 遍历List
(1)持久层添加用户批量增加方法
(2)映射文件添加相关标签
(3)测试类新建测试方法
(4)运行结果
3. 遍历Map
(1)持久层添加多条件查询方法
(2)映射文件添加相关标签
(3)测试类新建测试方法
(4)运行结果
后言----查错
相关导读
Mybatis专栏:
Mybatis系列专栏 | MyBatis入门配置 |
Mybatis入门案例【超详细】 | |
MyBatis配置文件 —— 相关标签详解 | |
Mybatis模糊查询——三种定义参数方法和聚合查询、主键回填 | |
Mybatis动态SQL查询 --(附实战案例--8888个字--88质量分) | |
Mybatis分页查询——四种传参方式 | |
Mybatis一级缓存和二级缓存(带测试方法) | |
Mybatis分解式查询 | |
Mybatis关联查询【附实战案例】 | |
MyBatis注解开发---实现增删查改和动态SQL | |
MyBatis注解开发---实现自定义映射关系和关联查询 |
前言
由于这是动态SQL,和先前得有些不一样,这里我们新建一个持久层接口UserMapper2和Mybatis映射文件UserMapper2.xml,测试类TestUserMapper2
持久层接口UserMapper2
package com.mybatisstudy.mapper;import com.mybatisstudy.pojo.User;public interface UserMapper2 { }
Mybatis映射文件UserMapper2.xml
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.mybatisstudy.mapper.UserMapper2"></mapper>
测试类TestUserMapper2
import com.mybatisstudy.mapper.UserMapper2;import com.mybatisstudy.pojo.User;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.After;import org.junit.Before;import org.junit.Test;import java.io.InputStream;public class TestUserMapper2 { InputStream is = null; SqlSession session = null; UserMapper2 userMapper2 = null; //前置方法,不必重复代码 @Before public void before() throws Exception { System.out.println("前置方法执行·············"); // (1)读取核心配置文件 is = Resources.getResourceAsStream("SqlMapConfig.xml"); // (2)创建SqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); // (3)SqlSessionFactoryBuilder对象获取SqlSessionFactory对象 SqlSessionFactory factory = builder.build(is); // (4)SqlSessionFactory对象获取SqlSession对象 session = factory.openSession(); // (5)SqlSession对象获取代理对象 userMapper2 = session.getMapper(UserMapper2.class); } //后置方法,释放资源 @After public void after() throws Exception { System.out.println("后置方法执行·············"); session.close(); is.close(); }}
一、动态SQL---if标签
一个查询的方法的Sql语句不一定是固定的。比如电商网站的查询商品,用户使用不同条件查询,Sql语句就会添加不同的查询条件。此时就需要在方法中使用动态Sql语句。
<if> 标签内的Sql片段在满足条件后才会添加,用法为: <if test="条件"> 。例如:根据不同条件查询用户:
1. 持久层添加用户通用查询方法
// 用户通用查询 List<User> findByCondition(User user);
2. 映射文件添加相关标签
<!-- 动态_if --> <select id="findByCondition" parameterType="com.mybatisstudy.pojo.User" resultType="com.mybatisstudy.pojo.User"> select * from user where 1 = 1 <if test="username != null and username.length()!=0"> and 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> </select>
这里肯定就会有读者会问 where 后面为什么要加1 = 1,因为单单使用if标签的话,第一个条件是不用 and 关键字的,而后续的条件是需要加 and 关键字的。但是用户添加条件是随机的,没办法判断哪一个是第一个条件,因此在这里先添加1 = 1,就无需考虑后续的条件是否是第一个条件啦,但是后面还有更好的办法解决这个问题,在这里只是可以用这个方法解决目前的问题。
3. 测试类新建测试方法
// 测试通用查询方法 @Test public void testFindByCondition(){ User user = new User(); System.out.println("----------没有限制条件查询---------"); List<User> users = userMapper2.findByCondition(user); users.forEach(System.out::println); System.out.println("----------用户名带有name限制条件查询---------"); user.setUsername("%name%"); List<User> users1 = userMapper2.findByCondition(user); users1.forEach(System.out::println); System.out.println("----------姓名带有name和性别是man限制条件查询---------"); user.setSex("woman"); List<User> users3 = userMapper2.findByCondition(user); users3.forEach(System.out::println); }
4. 运行结果
if中的条件不能使用&&/||,而应该使用and/or
if中的条件可以直接通过属性名获取参数POJO的属性值,并且该值可以调用方法。
二、动态SQL---where标签
OK,上述的问题的彩蛋来了,就是这个where标签,
<where> 可以代替sql中的where 1=1 和第一个and,更符合程序员的开发习惯,使用 <where> 后的映射文件如下:
1. 映射文件添加相关标签
<!-- 动态_if用where --> <select id="findByCondition" resultType="User" parameterType="User"> 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>
2. 测试类新建测试方法
这里不用新增,直接测试即可
3. 运行结果
因此我们以后就不用添加那个什么1 = 1了
三、动态SQL---set标签
<set> 标签用在update语句中。借助 <if> ,可以只对有具体值的字段进行更新。 <set> 会自动添加set关键字,并去掉最后一个if语句中多余的逗号。
1. 持久层添加用户更新方法
// 更新用户 void update(User user);
2. 映射文件添加相关标签
<!-- 动态_set 更新用户 --> <update id="update" parameterType="User"> update user <set> <if test="username != null and username.length()!=0"> username = #{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> </set> <where> id = #{id} </where> </update>
3. 测试类新建测试方法
// 测试更新用户方法 @Test public void testUpdate(){ User user = new User(); user.setId(4); user.setUsername("man4"); userMapper2.update(user); session.commit(); }
4. 运行结果
这里想整一个效果图,但是没想到帧率不够,最后居然绿屏了,但是不影响我们继续学习哈哈哈,理解到位即可害嗨嗨
四、动态SQL---choose和wen和otherwise标签
这些标签表示多条件分支,类似JAVA中的 switch...case 。 <choose> 类似switch , <when> 类似 case , <otherwise> 类似 default ,用法如下:
1. 持久层添加用户通用查询方法
这里就沿用那个通用查询方法即可
2. 映射文件添加相关标签
<select id="findByCondition" resultType="User" parameterType="user"> select * from user <where> <choose> <when test="username.length() < 5"> username like #{username} </when> <when test="username.length() < 10"> username = #{username} </when> <otherwise> id = 1 </otherwise> </choose> </where> </select>
这段代码的含义就是当用户名的长度小于(不等于)5的时候,使用模糊查询,查询返回的是泛型为USer的List集合对象,list长度不定;当用户名大于等于5,小于10的时候,使用精确查询,查询指定用户名的用户,返回的是泛型为USer的List集合对象,list长度为1或者0;当用户名长度大于等于10的时候,返回的是id为1的用户。
3. 测试类新建测试方法
// 测试通用查询方法——用户名 @Test public void testFindByCondition1(){ User user = new User(); System.out.println("------------设用户名字长度为2------------"); user.setUsername("%on%"); List<User> users = userMapper2.findByCondition(user); users.forEach(System.out::println); System.out.println("------------设用户名字长度为5------------"); user.setUsername("%lions%"); users = userMapper2.findByCondition(user); users.forEach(System.out::println); System.out.println("------------设用户名字长度为9------------"); user.setUsername("T_no_name"); users = userMapper2.findByCondition(user); users.forEach(System.out::println); System.out.println("------------设用户名字长度为10------------"); user.setUsername("dddddddddd"); users = userMapper2.findByCondition(user); users.forEach(System.out::println); System.out.println("------------设用户名字长度为12------------"); user.setUsername("programmer_1"); users = userMapper2.findByCondition(user); users.forEach(System.out::println); }
4. 运行结果
OK,其实从结果集和运行的SQL语句我们都可以得出,该映射文件的标签确实是验证了咱们刚刚的说法
五、动态SQL---foreach标签
<foreach> 类似JAVA中的for循环,可以遍历集合或数组。 <foreach> 有如
下属性:
collection:遍历的对象类型 open:开始的sql语句 close:结束的sql语句 separator:遍历每项间的分隔符 item:表示本次遍历获取的元素,遍历List、Set、数组时表示每项元素,遍历map时表示键值对的值。 index:遍历List、数组时表示遍历的索引,遍历map时表示键值对的键。1. 遍历数组
(1)持久层添加用户批量删除方法
// 用户批量删除 void deleteBatch(int[] ids);
(2)映射文件添加相关标签
<!-- 批量删除 遍历数组--> <delete id="deleteBatch" parameterType="int"> delete from user <where> <foreach collection="array" item="id" open="id in(" close=")" separator=","> #{id} </foreach> </where> </delete>
其实这里对应的SQL语句就是:
delete from user in (?,?,?,...)
(3)测试类新建测试方法
// 测试用户批量删除方法 @Test public void testDeleteBatch(){ int[] ids = {4,8}; userMapper2.deleteBatch(ids); session.commit(); }
(4)运行结果
运行前和运行后进行对比
运行后,四和八对应的记录确实是被删除了
2. 遍历List
<foreach> 遍历List和Set的方法是一样的,我们使用 <foreach> 遍历List进行批量添加。
(1)持久层添加用户批量增加方法
// 批量增加用户 void insertBatch(List<User> users);
(2)映射文件添加相关标签
<!-- 批量增加用户 --> <insert id="insertBatch" parameterType="User"> insert into user values <foreach collection="list" item="user" separator=","> (null,#{user.username},#{user.sex},#{user.address}) </foreach> </insert>
这里对应的SQL语句则是:
insert into user values(null,username,sex,address)*N
N可以为大于或等于1的数
其中肯定会有人问到了,为什么id要为null,其实这里id是主键,我们建库建表的时候就已经设置了这里是自增字段,因此我们无需重复操作,如果设置有和表里面的id重复,说不定还会报错
(3)测试类新建测试方法
// 测试批量增加用户方法 @Test public void testInsertBatch(){ List<User> list = new ArrayList<>(); list.add(new User("man1","man","Beijing")); list.add(new User("man1","man","Beijing")); list.add(new User("man1","man","Beijing")); list.add(new User("man1","man","Beijing")); list.add(new User("man1","man","Beijing")); list.add(new User("man1","man","Beijing")); userMapper2.insertBatch(list); session.commit(); }
(4)运行结果
运行前和运行后进行对比
OK,通过对比,确实是增加了相关记录,这里的id是因为我测试过很多次了,所以比较大,大家不用在意这些哈哈哈,侧面反映我是很认真在写的,期待小伙伴的支持
3. 遍历Map
下面我们使用 <foreach> 遍历Map进行多条件查询。
(1)持久层添加多条件查询方法
/** * 多条件查询 * @param map 查询的键值对 键:属性名 值:属性值 * @return */ List<User> findUser(@Param("queryMap") Map<String,Object> map);
(2)映射文件添加相关标签
<!-- 多条件查询 遍历map--> <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>
这里对应的代码段其实就是:
select * from user where (? = ?) and (? = ?)
就像我们在淘宝,拼多多和京东上买东西使用筛选一样
(3)测试类新建测试方法
// 测试多条件查询方法 @Test public void testFindUser(){ Map<String,Object> map = new HashMap<>(); // 这里筛选性别为man和地址为Beijing的结果集 map.put("sex","man"); map.put("address","Beijing"); List<User> users = userMapper2.findUser(map); users.forEach(System.out::println); // 再测试一下 map.clear(); // 这里筛选地址为Beijing和用户名为man1的结果集 map.put("address","Beijing"); map.put("username","man1"); users = userMapper2.findUser(map); users.forEach(System.out::println); }
(4)运行结果
先看用户表数据
执行方法,观察结果是否一致 (是的,确实一致),不一致怎么会放出来呢
OK,这里确实保持一致,动态查询就学到这里了,后续会继续更新相关内容滴,敬请关注! !!
后言----查错
如果执行过程中有错误的话,不妨看看有没有导错包和导错类,下面就是上面用到相关的类用到的导包
持久层接口用到的包
package com.mybatisstudy.mapper;import com.mybatisstudy.pojo.User;import org.apache.ibatis.annotations.Param;import java.util.List;import java.util.Map;
测试类用到的包
import com.mybatisstudy.mapper.UserMapper2;import com.mybatisstudy.pojo.User;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.After;import org.junit.Before;import org.junit.Test;import java.io.InputStream;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;