Mybatis(七)——动态SQL(if、where、foreach标签)

在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>

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值