在SQL映射文件中,可能会有下列的情况:
- 根据名字查询学生
select * from student where stuname = #{stuName}
- 根据年龄查询学生
select * from student where stunage = #{stuAge}
- 根据名字和年龄查询学生
select * from student where stuname = #{stuName} and stunage = #{stuAge}
这种情况在映射文件中写三个select标签显得有点冗余,可以使用sql标签的方式进行简化
方法一:使用 < if > 标签
根据参数是否为空来决定最终的sql查询条件
<select id="queryStudent" parameterType="Student" resultType="Student">
select * from student where 1=1
<if test="stuName != null and stuName != ''">
and stuname = #{stuname}
</if>
<if test="stuAge != null and stuAge != 0">
and stuage = #{stuage}
</if>
</select>
注意:每一个if标签中的sql语句中都有and
,如果第一个if标签中不加and
,万一stuName为空且stuAge不为空,sql语句就是select * from student where and stuage = #{stuage}
,就会出现错误。所以最好每一个if标签中都添加上and
,然后再在where
后面添加1=1
,这样的话,sql语句就不会出错了。还需要注意的一点是:if标签中属性名必须于实体类的属性保持一致,注意大小写。而sql语句中就无需关注大小写。
方法二:使用 < where > 标签
<select id="queryStudent" parameterType="Student" resultType="Student">
select * from student
<where>
<if test="stuName != null and stuName != ''">
and stuname = #{stuname}
</if>
<if test="stuAge != null and stuAge != 0">
and stuage = #{stuage}
</if>
</where>
</select>
where标签根据sql语句自动判断是否需要第一个条件的and,保证sql语句中不会出现多于的and
,比第一种方法简单
< foreach > 标签
考虑下面这种情况,如果要查询一组学生,这组学生的学号在一个集合里,查询语句如下
select * from student where stuno in (1,2,3)
如果要遍历的话,我们可以采用< foreach >标签
< foreach> 元素主要用在构建 in 条件中,它可以在 SQL 语句中迭代一个集合。
foreach元素的属性主要有 item,index,collection,open,separator,close。
- collection 参数名称,根据Mapper接口的参数名确定,也可以使用@Param注解指定参数名
- item 表示集合中每一个元素进行迭代时的别名,
- index 指 定一个名字,用于表示在迭代过程中,每次迭代到的位置,
- open 表示该语句以什么开始,
- separator 表示在每次进行迭代之间以什么符号作为分隔 符,
- close 表示以什么结束。
在使用 元素时,最关键、最容易出错的是 collection 属性,该属性是必选的,但在不同情况下该属性的值是不一样的,主要有以下 3 种情况:
- 如果传入的是单参数且参数类型是一个 List,collection 属性值为 list。
- 如果传入的是单参数且参数类型是一个 array 数组,collection 的属性值为 array。
- 如果传入的参数是多个,需要把它们封装成一个 Map,当然单参数也可以封装成 Map。Map 的 key 是参数名,collection 属性值是传入的 List 或 array 对象在自己封装的 Map 中的 key。
foreach迭代的类型:数据、对象数组、集合、属性(其类型为List)等
测试foreach迭代的类型——属性。
首先在entity包中新建一个IdList类,其代码如下;
public class IdList {
private List<Integer> idList;//链表里面存放用户的id值
public List<Integer> getIdList() {
return idList;
}
public void setIdList(List<Integer> idList) {
this.idList = idList;
}
}
SQL映射文件
<select id="queryFromIdList" parameterType="IdList" resultType="Student">
select * from student
<where>
<if test="idList != null and idList.size > 0">
<foreach collection="idList" open="stuno in (" close=")"
item="str" separator=",">
#{str}
</foreach>
</if>
</where>
</select>
完整的SQL语句为select * from student where stuno in ( str )
,item的属性值就是括号中的内容(str),是要迭代的对象。item的属性值可以写任意值,而"str"之前和之后的内容不是要迭代的对象,所以分别写在open和close中。separator的属性值","表示迭代的对象之间以逗号分隔开。
测试类的代码如下
public static void queryFromIdList(){
InputStream stream = Student.class.getClassLoader().getResourceAsStream("conf.xml");
SqlSessionFactory ssf=new SqlSessionFactoryBuilder().build(stream);
SqlSession session=ssf.openSession();
StudentMapper studentMapper = session.getMapper(StudentMapper.class);
IdList idList = new IdList();
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
idList.setIdList(list);//查询id值为1,2,3的学生的信息
List<Student> students = studentMapper.queryFromIdList(idList);
session.commit();
System.out.println(students);
session.close();
}
测试foreach迭代的类型——简单类型的数组
SQL映射文件
<select id="queryFromArray" parameterType="int[]" resultType="Student">
select * from student
<where>
<if test="array != null and array.length > 0">
<foreach collection="array" open="stuno in (" close=")"
item="str" separator=",">
#{str}
</foreach>
</if>
</where>
</select>
注意:if标签和collection中的属性值为array
测试类
public static void queryFromArray(){
InputStream stream = Student.class.getClassLoader().getResourceAsStream("conf.xml");
SqlSessionFactory ssf=new SqlSessionFactoryBuilder().build(stream);
SqlSession session=ssf.openSession();
StudentMapper studentMapper = session.getMapper(StudentMapper.class);
int[] stuNos = new int[]{1,2,3};
List<Student> students = studentMapper.queryFromArray(stuNos);
session.commit();
System.out.println(students);
session.close();
}
测试foreach迭代的类型——list
SQL映射文件
<select id="queryFromList" parameterType="list" resultType="Student">
select * from student2
<where>
<if test="list != null and list.size > 0">
<foreach collection="list" open="stuno in (" close=")"
item="str" separator=",">
#{str}
</foreach>
</if>
</where>
</select>
测试类
public static void queryFromList(){
InputStream stream = Student.class.getClassLoader().getResourceAsStream("conf.xml");
SqlSessionFactory ssf=new SqlSessionFactoryBuilder().build(stream);
SqlSession session=ssf.openSession();
StudentMapper studentMapper = session.getMapper(StudentMapper.class);
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
List<Student> students = studentMapper.queryFromList(list);
session.commit();
System.out.println(students);
session.close();
}
测试foreach迭代的类型——对象数组
SQL映射文件
<select id="queryFromObjectArray" parameterType="Object[]" resultType="Student">
select * from student2
<where>
<if test="array != null and array.length > 0">
<foreach collection="array" open="stuno in (" close=")"
item="str" separator=",">
#{str.stuNo}
</foreach>
</if>
</where>
</select>
注意:如果foreach遍历的是对象数组,则parameterType的值规定为Object[]
,注意修改成#{str.stuNo}
测试类
public static void queryFromObjectArray(){
InputStream stream = Student.class.getClassLoader().getResourceAsStream("conf.xml");
SqlSessionFactory ssf=new SqlSessionFactoryBuilder().build(stream);
SqlSession session=ssf.openSession();
StudentMapper studentMapper = session.getMapper(StudentMapper.class);
Student stu1= new Student();
stu1.setStuNo(1);
Student stu2= new Student();
stu2.setStuNo(2);
Student stu3= new Student();
stu3.setStuNo(3);
Student[] students = new Student[]{stu1,stu2,stu3};
List<Student> stus = studentMapper.queryFromObjectArray(students);
session.commit();
System.out.println(stus);
session.close();
}
SQL片段
如果某段sql语句重复使用,可以将其提取出来
以foreach遍历对象数组为例,将下列sql语句做成sql片段
<where>
<if test="array != null and array.length > 0">
<foreach collection="array" open="stuno in (" close=")"
item="str" separator=",">
#{str.stuNo}
</foreach>
</if>
</where>
SQL映射文件
在StudentMapper.xml文件中,添加如下语句
<sql id="objectArray">
<where>
<if test="array != null and array.length > 0">
<foreach collection="array" open="stuno in (" close=")"
item="str" separator=",">
#{str.stuNo}
</foreach>
</if>
</where>
</sql>
在需要用到上述sql语句的sql标签中,做如下修改
<select id="queryFromObjectArray" parameterType="Object[]" resultType="Student">
select * from student2
<include refid="objectArray"></include>
</select>
注意:如果sql片段与需要引用的sql标签不在同一个文件中,比如id值为objectArray2的sql片段在StudentMapper2.xml中,
而在StudentMapper.xml需要用到此sql片段,则引用时,需要加上sql片段的mapper命名空间namespace,
如<include refid="com.santiago.mapper.StudentMapper2.objectArray2"></include>