一、动态SQL语句
- 何为动态SQL语句:
通过mybatis提供的< if > ,< where >,< foreach >标签对条件做出判断以实现动态拼接SQL语句,主要用于解决查询条件不确定的情况,它会根据用户提交的查询条件进行查询。其主要是SQL语句where关键字后面部分发生变化。
- 注意事项:
在映射文件中的动态 SQL 中若出现大于号(>)、小于号(<)、大于等于号(>=),小于等于号(<=)等符号,最好将其转换为实体符号。否则,XML 可能会出现解析出错问题。
重点:特别是对于小于号(<),在 XML 文件中是绝不能出现的。否则解析 映射文件 会出错。
- 实体符号表:
< | 小于 | <; |
---|---|---|
> | 大于 | >; |
>= | 大于等于 | >;= |
<= | 小于等于 | <;= |
- 下面介绍这几种标签:
(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);
}
}
二、思维大纲
如有不足之处请大家指正哈!