文章目录:
1.什么是动态SQL?
动态 SQL,通过 MyBatis 提供的各种标签对条件作出判断以实现动态拼接SQL 语句。这里的条件判断使用的表达式为 OGNL 表达式。常用的动态 SQL标签有<if>、<where>、<foreach>、<sql>等。
MyBatis 的动态 SQL 语句,与 JSTL 中的语句非常相似。
动态 SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行查询。提交的查询条件不同,执行的 SQL 语句不同。若将每种可能的情况均逐一列出,对所有条件进行排列组合,将会出现大量的SQL 语句。此时,可使用动态 SQL 来解决这样的问题。
使用动态SQL时,dao接口中方法的形参要使用Java对象。
2.MyBatis中的动态SQL
2.1 动态SQL——if标签
2.1.1 语法格式
<if test="boolean判断结果"> <!--要么为true、要么为false-->
sql语句的部分
</if>
<!-- 对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片段断拼接到其所在的 SQL 语句中。 -->
2.1.2 应用举例
package com.bjpowernode.dao;
import com.bjpowernode.entity.Student;
import java.util.List;
/**
*
*/
public interface StudentDao {
//if
List<Student> selectIf(Student student);
}
<!-- if
test: 使用对象的属性值作为条件
-->
<select id="selectIf" resultType="com.bjpowernode.entity.Student">
select *
from student
where id=-1
<if test="name!=null and name!=''">
or name=#{name}
</if>
<if test="age>0">
or age=#{age}
</if>
</select>
<!--
<if/>标签的中存在一个比较麻烦的地方:需要在 where 后手工添加 id=-1的子句。
因为,若 where 后的所有<if/>条件均为 false,而 where 后若又没有 id=-1 子句,则 SQL 中就会只剩下一个空的 where,SQL 出错。
所以,在where 后,需要添加子句 id=-1,以防止这种情况的发生。但当数据量很大时,会严重影响查询效率。
-->
@Test
public void testSelectIf() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentDao studentDao=session.getMapper(StudentDao.class);
Student student=new Student();
student.setName("张起灵");
student.setAge(20);
List<Student> students=studentDao.selectIf(student);
students.forEach( stu -> System.out.println("stu === " + stu) );
session.close();
}
根据上面三个代码块,将其中的内容转为等价的 sql 语句如下:👇👇👇
select *
from student
where id=-1 or name="张起灵" or age=20
2.2 动态SQL——where标签
2.2.1 语法格式
<where>
其他动态sql
</where>
2.2.2 应用举例
package com.bjpowernode.dao;
import com.bjpowernode.entity.Student;
import java.util.List;
/**
*
*/
public interface StudentDao {
//where
List<Student> selectWhere(Student student);
}
<!-- where -->
<select id="selectWhere" resultType="com.bjpowernode.entity.Student">
select *
from student
<where>
<if test="name!=null and name!=''">
or name=#{name}
</if>
<if test="age>0">
or age=#{age}
</if>
</where>
</select>
<!--
使用<where/>标签,在有查询条件时,可以自动添加上 where 子句;没有查询条件时,不会添加 where 子句。
需要注意的是,第一个<if/>标签中的SQL 片断,可以不包含 and。不过,写上 and 也不错,where标签会将离它最近的 and 或者 or 删掉。
但其它<if/>中 SQL 片断的 and,必须要求写上。否则 SQL 语句将拼接出错
-->
@Test
public void testSelectWhere() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentDao studentDao=session.getMapper(StudentDao.class);
Student student=new Student();
student.setName("张起灵");
student.setAge(20);
List<Student> students=studentDao.selectWhere(student);
students.forEach( stu -> System.out.println("stu === " + stu) );
session.close();
}
根据上面三个代码块,将其中的内容转为等价的 sql 语句如下:👇👇👇
select *
from student
where id=-1 or name="张起灵" or age=20
2.3 动态SQL——foreach标签
2.3.1 语法格式
<foreach collection="集合类型" open="开始的字符" close="结束的字符" item="集合中的成员" separator="集合成员之间的分隔符">
#{item的值}
</foreach>
<!--
如果dao接口中方法的形参是数组,则collection="array"
如果dao接口中方法的形参是List,则collection="list"
#item的值}:获取集合成员的值
-->
2.3.2 应用举例1(简单类型)
package com.bjpowernode.dao;
import com.bjpowernode.entity.Student;
import java.util.List;
/**
*
*/
public interface StudentDao {
//for-each 1
List<Student> selectForeachOne(List<Integer> idlist);
}
<!-- foreach第一种方式,循环简单类型的List: List<Integer> -->
<select id="selectForeachOne" resultType="com.bjpowernode.entity.Student">
select *
from student
<if test="list!=null and list.size>0">
where id in
<foreach collection="list" open="(" close=")" separator="," item="stuid">
#{stuid}
</foreach>
</if>
</select>
@Test
public void testSelectForeachOne() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentDao studentDao=session.getMapper(StudentDao.class);
List<Integer> idlist=new ArrayList<>();
idlist.add(1001);
idlist.add(1002);
idlist.add(1003);
List<Student> students=studentDao.selectForeachOne(idlist);
students.forEach( stu -> System.out.println("stu === " + stu));
session.close();
}
根据上面三个代码块,将其中的内容转为等价的 sql 语句如下:👇👇👇
select *
from student
where id in (1001,1002,1003)
2.3.2 应用举例2(对象类型)
package com.bjpowernode.dao;
import com.bjpowernode.entity.Student;
import java.util.List;
/**
*
*/
public interface StudentDao {
//for-each 2
List<Student> selectForeachTwo(List<Student> studentList);
}
<!-- foreach第二种方式,循环对象类型的List: List<Student> -->
<select id="selectForeachTwo" resultType="com.bjpowernode.entity.Student">
select *
from student
<if test="list!=null and list.size>0">
where id in
<foreach collection="list" open="(" close=")" separator="," item="stu">
#{stu.id}
</foreach>
</if>
</select>
@Test
public void testSelectForeachTwo() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentDao studentDao=session.getMapper(StudentDao.class);
List<Student> list=new ArrayList<>();
Student s1=new Student();
s1.setId(1001);
Student s2=new Student();
s2.setId(1002);
Student s3=new Student();
s3.setId(1003);
list.add(s1);
list.add(s2);
list.add(s3);
List<Student> students=studentDao.selectForeachTwo(list);
students.forEach( stu-> System.out.println("stu === " + stu));
session.close();
}
根据上面三个代码块,将其中的内容转为等价的 sql 语句如下:👇👇👇
select *
from student
where id in (1001,1002,1003)
2.4 动态SQL——sql标签
2.4.1 语法格式
<sql id="...">
sql语句
</sql>
<include refid="sql标签的id属性值"></include>
<!--
<sql/>标签用于定义 SQL 片断,以便其它 SQL 标签复用。
而其它标签使用该 SQL 片断,需要使用<include/>子标签。
该<sql/>标签可以定义 SQL 语句中的任何部分,所以<include/>子标签可以放在动态 SQL 的任何位置。
-->
2.4.2 应用举例
package com.bjpowernode.dao;
import com.bjpowernode.entity.Student;
import java.util.List;
/**
*
*/
public interface StudentDao {
//代码片段
List<Student> selectSql(List<Student> studentList);
}
<!-- 定义代码片段 -->
<sql id="selectStudent">
select id,name,age from student
</sql>
<sql id="studentFieldList">
where id in
</sql>
<select id="selectSql" resultType="com.bjpowernode.entity.Student">
<include refid="selectStudent"></include>
<if test="list!=null and list.size>0">
<include refid="studentFieldList"></include>
<foreach collection="list" open="(" close=")" separator="," item="student">
#{student.id}
</foreach>
</if>
</select>
@Test
public void testSelectSql() {
SqlSession session = MyBatisUtil.getSqlSession();
StudentDao studentDao=session.getMapper(StudentDao.class);
List<Student> list=new ArrayList<>();
Student s1=new Student();
s1.setId(1001);
Student s2=new Student();
s2.setId(1002);
Student s3=new Student();
s3.setId(1003);
list.add(s1);
list.add(s2);
list.add(s3);
List<Student> students=studentDao.selectSql(list);
students.forEach( stu-> System.out.println("stu === " + stu));
session.close();
}
根据上面三个代码块,将其中的内容转为等价的 sql 语句如下:👇👇👇
select id,name,age
from student
where id in (1001,1002,1003)