Mybatis框架----->(6) 深入理解Mybatis的动态SQL语句

一、动态SQL语句

  • 何为动态SQL语句:

通过mybatis提供的< if > ,< where >,< foreach >标签对条件做出判断以实现动态拼接SQL语句,主要用于解决查询条件不确定的情况,它会根据用户提交的查询条件进行查询。其主要是SQL语句where关键字后面部分发生变化。

  • 注意事项:

在映射文件中的动态 SQL 中若出现大于号(>)、小于号(<)、大于等于号(>=),小于等于号(<=)等符号,最好将其转换为实体符号。否则,XML 可能会出现解析出错问题。
重点特别是对于小于号(<),在 XML 文件中是绝不能出现的。否则解析 映射文件 会出错

  • 实体符号表:
< 小于 &lt;
> 大于 &gt;
>= 大于等于 &gt;=
<= 小于等于 &lt;=
  • 下面介绍这几种标签:

(1)< if >标签

语法格式:
<if test="判断java对象的属性值">
    部分sql语句
</if>
  • 定义接口中的方法
List<Student> selectStudentIf(Student student);
  • 映射文件
<select id="selectStudentIf" resultType="Student">
    <include refid="studentSql"/>
    where 
    <if test="name!=null and name!=''">
        name=#{name}
    </if>
    <if test="age>0">
        or age>#{age}
    </if>
</select>

这里定义了SQL语句代码片段,方便以后调用,避免代码冗余

使用步骤:
1.先定义 < sql id=“自定义名称唯一”> sql语句, 表名,字段等 < /sql>
2.再使用, < include refid=“id的值” />

<sql id="studentSql" >
    select id,name,age,email from student
</sql>
  • 定义测试方法
@Test
public void testSelectStudenIf(){
    
    
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    Student student = new Student();
    student.setName("李四");
    student.setAge(20);
    List<Student> studentList = dao.selectStudentIf(student);

    for (Student student1:studentList){
    
    
        System.out.println("学生if="+student1);
    }
}

这里如把测试方法中的代码姓名这段代码注释掉

Student student = new Student();
//student.setName("李四");
student.setAge(20);
List<Student> studentList = dao.selectStudentIf(student);

那么执行的SQL语句则会出错:

SQL:select id,name,age,email from student where or age>?

缺陷
当后面一个if语句不满足或者都不满足时,SQL语句会拼接成
select id,name,age,email from student where or age>?
select id,name,age,email from student where
这样的SQL语句明显是错误的

小技巧
可以在where后面加入一个满足条件(真子句),例如:where id>0
这样SQL语句就变成了可执行语句了
select id,name,age,email from student where id>0 or age>?
但当数据量很大时,会严重影响查询效率。

改进后的映射文件为:

<select id="selectStudentIf" resultType="Student">
    <include refid="studentSql"/>
    where id>0
    <if test="name!=null and name!=''">
       and  name=#{name}
    </if>
    <if test="age>0">
        or age>#{age}
    </if>
</select>

里面where关键字后面添加了一个真子句id>0并在name前面加多了and
这样执行SQL语句则变成:
SQL:select id,name,age,email from student where id>0 or age>?

(2)< where >标签

语法格式:
<where> 
	其他动态 sql 
</where>
< where >:解决< if >标签带来的小缺陷

< where > 用来包含 多个< if> 的
1、当多个 if 有一个成立的,< where >会自动增加一个WHERE关键字
2、当后面 if 条件有些不成立时,可以去掉 if 中多余的 and ,or等
3、当后面的 if 条件都不满足时,WHERE关键字也会去掉

  • 定义接口中的方法
List<Student> selectStudentWhere(Student student);
  • 映射文件
<select id="selectStudentWhere" resultType="Student">
    <include refid="studentSql"></include>
    <where>
        <if test="name!=null and name!=''">
            name=#{name}
        </if>
        <if test="age>0">
            or age>#{age}
        </if>
    </where>
</select>
  • 定义测试方法
@Test
public void testSelectStudenWhere(){
    
    
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);

    Student student = new Student();
    //student.setName("李四");
    student.setAge(20);
    List<Student> studentList = dao.selectStudentWhere(student);

    for (Student student1:studentList){
    
    
        System.out.println("学生where="+student1);
    }
}

(3)< foreach>标签

语法格式:
<foreach collection="" open="" close="" item="" separator=""> 
	#{item 的值} 
</foreach> 

< foreach >标签用于实现对于数组与集合的遍历,主要用在sql语句的 in 语句中

1、这里先不用标签把SQL语句拼接出来

例如:查询学生 id 是 1001,1002,1003

select * from student where id in (1001,1002,1003)

这里定义一个测试方法来拼接上面的SQL语句

@Test
public void testfor(){
    
    
    List<Integer> list=new ArrayList<>();
    list.add(1001);
    list.add(1002);
    list.add(1003);
    //String sql = "select * from student where id in(1001,1002,1003);
    String sql ="select * from student where id in";
    StringBuilder builder = new StringBuilder(sql);
    int init=0;
    int len=list.size();
    //添加开始的(
    builder.append("(");
    for (Integer i:list){
    
    
        builder.append(i).append(",");
    }
    //将最后一个逗号删除
    builder.deleteCharAt(builder.length()-1);
    //循环结束
    builder.append(")");
    sql = builder.toString();
    System.out.println("sql=="+sql);
}

显然以上代码很长很臭,下面进行改进…

2、通过< foreach >标签把SQL语句拼接出来

用法一:遍历 List<简单类型>

  • 定义接口中的方法
List<Student> selectStudentForeachOne(List<Integer> list);
  • 映射文件
<select id="selectStudentForeachOne" resultType="Student">
    <include refid="studentSql"/> where id in
    <foreach collection="list" item="myid" open="(" close=")" separator=",">
        #{myid}
    </foreach>
</select>

解析标签中的属性
1、collection:表示接口中的方法参数的类型,
如果是数组使用array , 如果是list集合使用list
2、item:自定义的,表示数组和集合成员的变量,相当于Integer i中的 i 变量
for (Integer i:list){
builder.append(i).append(",");
}
3、open:循环开始是的字符“(”
4、close:循环结束时的字符“)”
5、separator:集合成员之间的分隔符“,”

  • 定义测试方法
@Test
public void testSelectStudenForeachOne(){
    
    
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);
    List<Integer> list=new ArrayList<>();
    list.add(1001);
    list.add(1002);
    list.add(1003);
    List<Student> studentList = dao.selectStudentForeachOne(list);
    for (Student student1:studentList){
    
    
        System.out.println("学生foreachone="+student1);
    }
}

用法二:遍历 List<对象类型>

  • 定义接口中的方法
List<Student> selectStudentForeachTwo(List<Student> studentlist);
  • 映射文件
<select id="selectStudentForeachTwo" resultType="Student">
    <include refid="studentSql"/> where id in (
    <foreach collection="list" item="stu" separator=",">
        #{stu.id}
    </foreach>
    )
</select>

注意:这里 item 的值 stu 只是对应的Java对象

  • 定义测试方法
@Test
public void testSelectStudenForeachTwo(){
    
    
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);

    List<Student> stulist=new ArrayList<>();
    Student s1 = new Student();
    s1.setId(1001);
    stulist.add(s1);

    Student s2 = new Student();
    s2.setId(1002);
    stulist.add(s2);

    List<Student> studentList = dao.selectStudentForeachTwo(stulist);

    for (Student student1:studentList){
    
    
        System.out.println("学生foreachtwo="+student1);
    }
}

二、思维大纲

在这里插入图片描述

如有不足之处请大家指正哈!

猜你喜欢

转载自blog.csdn.net/hcz666/article/details/113132501
今日推荐