MyBatis之动态sql
需要掌握动态SQL的使用的方法
3.动态sql
3.1常见的动态查询条件
- if,就是判定
- choose
- where等价于sql中的where
- set,灵活的去掉关键字
- trim,设置更新语句
- foreach,迭代形成一个集合
3.2if和where用于查询
1.案例
<!-- selectStudent查询学生-->
<resultMap id="testStudent" type="Student">
<result column="id" property="id"/>
<result column="name" property="student_name"/>
</resultMap>
//注意查询前面需要设置and不然的拼接sql的时候不能正确的执行
<select id="selectStudent" resultMap="testStudent">
select * from student
<where>
<if test="id!=null">
and id=#{id}
</if>
<if test="student_name!=null and student_name!=''">
and name like concat('%',#{student_name},'%')
</if>
limit 0,1
</where>
</select>
接口
Student selectStudent(@Param("id") Integer id,@Param("student_name")String name);
测试代码
@Test
public void selectStudentTest() {
SqlSession sqlSession = null;
int count = 0;
try {
sqlSession = MyBatisUtil.createSqlSession();
Student student = sqlSession.getMapper(StudentMapper.class).selectStudent(null,"张");
System.out.println("测试动态sql");
System.out.println(student.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
MyBatisUtil.closeSqlSession(sqlSession);
}
}
3.3if和set用于修改
其实这个案例只是用来进行测试的,真正的案例中是不会使用set和if组合进行null判断的,因为在处理请求的时候就进行了判断,并且一般都是更新全部的数据而不是只更新部分的数据
解决更新的时候不会出现某个字段的为null的时候也把对应的字段更新了
数据库数据
类的代码
更新的sql
- 注意每个的后面需要带上一个逗号
<!-- 动态的更新学生的信息-->
<update id="updateStudent2" parameterType="cn.smbms.pojo.Student">
update student
<set>
<if test="student_name!=null and student_name!=''">name=#{student_name},</if>
<if test="sex!=null and sex!=''">sex=#{sex},</if>
</set>
where id=#{id}
</update>
测试代码
- 假设只更新名字不更新性别
sqlSession = MyBatisUtil.createSqlSession();
int line= sqlSession.getMapper(StudentMapper.class).updateStudent2(new Student(1,"张三",""));
sqlSession.commit();
System.out.println("影响的行数");
System.out.println(line);
图 1 改变后的张的信息为张三
3.4if和trim类似if和set的用法
改造3.3中案例的sql代码
注意格式就可以
<!-- 改造成if+trim的用法-->
<update id="updateStudent2" parameterType="cn.smbms.pojo.Student">
update student
<trim prefix="set" suffixOverrides="," suffix="where id=#{id}">
<if test="student_name!=null and student_name!=''">name=#{student_name},</if>
<if test="sex!=null and sex!=''">sex=#{sex},</if>
</trim>
</update>
图2 修改后的信息
3.5foreach完成复杂查询
- 集合
- 数组
- map都可以进行处理
案例:查询多个id的学生的信息,传入的数据是一个数组
foreach常见的属性
- item指定的是迭代的别名,比如我传入的是idx但是用的时候采用的是tid的形式
- index,每次迭代的位置
- open,表示从什么语句开始,比如in就是从(开始的
- close,表示从什么结束,in就是)结束
- separator,表示每次循环的时候采用的分隔符,比如说in就是逗号
- collection指定的是传入数据的类型,采用的是数组的类型的话就是array,list就是集合
- 如果传入的数据是多个参数的话可以采用map的形式
接口
//查询的数据是一个集合
List<Student> getIdsStudent(Integer[] idx);
sql代码
<!-- 查询数组中的数据 -->
<resultMap id="getIdsStudentMap" type="Student">
<result property="id" column="id"/>
<result property="student_name" column="name"/>
<result property="sex" column="sex"/>
</resultMap>
<select id="getIdsStudent" resultMap="getIdsStudentMap">
select * from student where id in
<foreach collection="array" item="tid" open="(" close=")" separator=",">
#{tid}
</foreach>
</select>
测试代码
- 查询id为1和2的信息
@Test
public void getIdsStudentTest() {
SqlSession sqlSession = null;
int count = 0;
try {
sqlSession = MyBatisUtil.createSqlSession();
Integer idx[]={1,2};
List<Student> students = sqlSession.getMapper(StudentMapper.class).getIdsStudent(idx);
sqlSession.commit();
System.out.println("查询指定指定id集合的数据");
System.out.println(students.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
MyBatisUtil.closeSqlSession(sqlSession);
}
}
图3 查询多条数据
3.6传入list集合的形式
只需要将3.5案例中的array的格式变成list集合的形式就可以了
接口定义
//查询的数据是一个集合
List<Student> getIdsStudentList(List<Integer> idx);
sql定义
<!-- 查询的数据是一个集合-->
<select id="getIdsStudentList" resultMap="getIdsStudentMap">
select * from student where id in
<foreach collection="list" item="tid" open="(" close=")" separator=",">
#{tid}
</foreach>
</select>
测试代码
sqlSession = MyBatisUtil.createSqlSession();
List<Integer> idx=new ArrayList();
idx.add(2);
idx.add(3);
List<Student> students = sqlSession.getMapper(StudentMapper.class).getIdsStudentList(idx);
sqlSession.commit();
System.out.println("查询指定指定id的List集合的数据");
System.out.println(students.toString());
图3 测试list
和array的区别在于把要传入的数据变成一个集合的形式就可以了
3.7传入map类型的形式
案例:想查询所有的指定学生性别和账号信息的所有的学生的信息
- 传入的参数是一个map。
- 第一个参数是sex,就是用来设置要查询的数据
- 第二个参数是idx,指定符合指定性别和id的学生的信息
接口定义
//查询的数据是一个map
List<Student> getMapStudentList(Map<String,Object> map);
sql定义
- collection中的值是map中的键的名称
<!--sql定义-->
<!-- idx是前面指定的key的值,但是里面保存的是集合-->
<select id="getMapStudentList" resultMap="getIdsStudentMap">
select * from student where sex=#{sex} and id in
<foreach collection="idx" item="tid" open="(" close=")" separator=",">
#{tid}
</foreach>
</select>
测试代码
sqlSession = MyBatisUtil.createSqlSession();
Map<String,Object> map=new HashMap<>();
List<Integer> idx=new ArrayList();
idx.add(1);
idx.add(2);
idx.add(3);
map.put("sex","男");
map.put("idx",idx);
List<Student> students = sqlSession.getMapper(StudentMapper.class).getMapStudentList(map);
sqlSession.commit();
System.out.println("查询指定指定id的List集合的数据");
System.out.println(students.toString());
图4 效果图
3.8小结
- mybatis可以接收的数据类型,基本的,对象,List,数组和map
- 不论是哪一种都可以放到map集合中去
- 放入map的之后会发生一定的变化,传入的值的类型变成了key的值的类型
- 入参的对象是基本类型就是key
- 入参的基本类型是对象,对象的属性就是key
- 入参的对象是list,默认的值就是list
- 入参的对象是数组,默认就是array
- 使用map键的值就和原来是一样的
3.9choose
原理和jstl以及用法都是类型的
- choose,进行判断的条件
- when,当条件符合的时候使用
- otherwise,当所有的情况都不是符合的时候采用
案例:根据id,name 进行查询,只提供一个即可,如果不提供的话默认的是根据性别进行查询
接口
// 根据id,name 进行查询,只提供一个即可,如果不提供的话默认的是查询默认男性的学生的信息
List<Student> getMapStudentChoose(@Param("id") Integer id,@Param("name")String name,@Param("sex") String sex);
sql
<select id="getMapStudentChoose" resultMap="getIdsStudentMap">
select * from student where 1=1
<choose>
<when test="id!=null">and id=#{id}</when>
<when test="name!=null">and name=#{name}</when>
<otherwise> and sex=#{sex}</otherwise>
</choose>
</select>
测试代码
@Test
public void getMapStudentChooseTest() {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtil.createSqlSession();
List<Student> students = sqlSession.getMapper(StudentMapper.class).getMapStudentChoose(null,null,"男");
sqlSession.commit();
System.out.println("采用choose的查询的方式");
System.out.println(students.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
MyBatisUtil.closeSqlSession(sqlSession);
}
}
图6 采用choose查询所有学生的信息
3.10分页
基于内存的分页。先查询出来所有的记录然后再进行根据起始的位置和容量进行取出数据。
案例:查询所有学生的信息,按照id进行降序。并且每次取出的数据为2条。
注意:分页的起点是从0开始的,也就是说limit后面的第一个数字就是起点的位置就是0
接口
/*
* currentPage当前是哪一页
* pageSize要分页的大小
* */
List<Student> getPage (@Param("currentPage") Integer currentPage,@Param("pageSize") Integer pageSize);
sql
<!-- 分页-->
<select id="getPage" resultMap="getIdsStudentMap">
select * from student
order by id desc
limit #{currentPage},#{pageSize}
</select>
测试代码
sqlSession = MyBatisUtil.createSqlSession();
List<Student> students = sqlSession.getMapper(StudentMapper.class).getPage(0,2);
System.out.println("分页查询");
System.out.println(students.toString());