Mybatis框架--动态SQL

什么是动态SQL?

  • MyBatis 的强大特性之一便是它的动态 SQL,它极大的简化了我们拼接SQL的操作。

  • 动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似。

  • MyBatis 采用功能强大的基于 OGNL 的表达式来消除其他元素。

    if
    choose(when,otherwise):分支选择 带了break的swtich-case
    trim(where,set)
    foreach

1.if条件判断

使用if条件判断,我们把所有的属性全部用if标签分步判断,需要携带那个字段,查询条件就带上这个字段:

<!--查询员工,要求携带那个字段,查询条件就带上这个字段-->
    <select id="getEmpByConditionIf" resultType="Bean.Employee">
        select * from tbl_employee
        <where>
            <!--test:判断表达式(OGNL)  从参数中取值进行判断
        遇见特殊符号应该去写转义字符
        &&:
        -->
            <if test="id!=null">
                id=#{id}
            </if>

            <if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
                and last_name like #{lastName}
            </if>

            <if test="email!=null and email.trim()!=&quot;&quot;">
                and email=#{email}
            </if>

            <if test="gender==0 or gender==1">
                and gender=#{gender}
            </if>
        </where>
    </select>

测试类:
我们测试一个名字中含有 “e” 字符,并且它的email为 “jerry@qq.com” 的员工信息

@Test
    public void testDynamicSQL05() {
        try {
            InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
            SqlSession sqlSession = sqlSessionFactory.openSession();

            EmployeeMapperDynamicSQL mapper = sqlSession.getMapper(EmployeeMapperDynamicSQL.class);
            Employee employee = new Employee(null, "%e%", "jerry@qq.com", null);
            List<Employee> emps = mapper.getEmpByConditionIf(employee);

            for (Employee emp : emps) {
                System.out.println(emp);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

运行结果:
我们看到打印出了一条信息,执行了两个sql语句
在这里插入图片描述

  • 转义字符表:
    在这里插入图片描述

2.Trim字符串拼接

上面的这个问题还可以使用trim字符串拼接来解决问题。

  • prefix:给拼串后的字符串加上一个前缀
  • prefixOverrides:去掉拼串后的字符串的一个前缀
  • suffix:给拼串后的字符串加上一个后缀
  • suffixOverrides:去掉拼串后字符串的一个前缀
  • set标签:在更新中使用,可以去除多余的逗号
<select id="getEmpByConditionTrim" resultType="Bean.Employee">
        select * from tbl_employee

        <trim prefix="where" suffixOverrides="and">
            <if test="id!=null">
                id=#{id} and
            </if>
            <if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
                last_name like #{lastName} and
            </if>
            <if test="email!=null and email.trim()!=&quot;&quot;">
                email=#{email} and
            </if>
            <if test="gender==0 or gender==1">
                gender=#{gender}
            </if>
        </trim>
    </select>

测试类:

@Test
    public void testDynamicSQL05() {
        try {
            InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
            SqlSession sqlSession = sqlSessionFactory.openSession();

            EmployeeMapperDynamicSQL mapper = sqlSession.getMapper(EmployeeMapperDynamicSQL.class);
            Employee employee = new Employee(null, "%e%", "jerry@qq.com", null);

            List<Employee> emps2 = mapper.getEmpByConditionTrim(employee);
            for (Employee emp : emps2) {
                System.out.println(emp);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

结果:
在这里插入图片描述

查询的时候如果某些条件可能没有带sql瓶装会有问题
1.给where后面加上 1=1,以后的条件都and xxx
2.mybatis使用where标签来将所有的查询条件包括在内。mybatis就会将where标签中拼装的sql,多出来的and或者or去掉
//where只会去掉第一个多出来的where或者or

3.choose选择

当有很多属性时,我们的choose标签只会选择进入其中的一个

<!--getEmpByConditionChoose-->
    <select id="getEmpByConditionChoose" resultType="Bean.Employee">
        select * from tbl_employee
        <where>
            /*如果带了id就用id查,如果带了lastName就用lastName查;只会进入其中一个*/
            <choose>
                <when test="id!=null">
                    id=#{id}
                </when>
                <when test="lastName!=null">
                    last_name like #{lastNmae}
                </when>
                <when test="email!=null">
                    email =#{email}
                </when>
                <otherwise>
                    gender = 0
                </otherwise>
            </choose>
        </where>
    </select>

4.Foreach集合遍历

动态 SQL 的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建 IN 条件语句的时候。

  • collection:指定要遍历的集合;list类型的参数会特殊处理封装在map中,map的key就叫list
  • item:将当前潜力出的元素赋值给指定的变量
  • separator:每个元素之间的分隔符 open:遍历出所有结果拼接一个开始的字符
  • close:遍历出所有结果拼接一个结束的字符
  • index:索引,遍历list的时候index就是是索引,item就是当前值
    遍历map的时候index表示就是map的key,item就是map的值
    #{变量名}就能取出变量的值也就是当前遍历出的元素
<!--getEmpsByConditionForeach-->
    <select id="getEmpsByConditionForeach" resultType="Bean.Employee" parameterType="java.util.List">
        select * from tbl_employee where id in
        
        <foreach collection="ids" item="item_id" separator=","
                 open="(" close=")">
                 #{item_id}
        </foreach>
    </select>
@Test
    public void testDynamicSQL07() {
        try {
            InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            EmployeeMapperDynamicSQL mapper = sqlSession.getMapper(EmployeeMapperDynamicSQL.class);

            List<Employee> list = mapper.getEmpsByConditionForeach(Arrays.asList(1, 14, 15, 16));
            for (Employee emp : list) {
                System.out.println(emp);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

运行结果:
在这里插入图片描述

批量插入:

<insert id="addEmps">
        <foreach collection="emps" item="emp" separator=";">
            insert into tbl_employee(last_name, email, gender)
            values(#{emp.lastName},#{emp.email},#{emp.gender})
        </foreach>
    </insert>
@Test
    public void testDynamicSQL08() {
        try {
            InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            EmployeeMapperDynamicSQL mapper = sqlSession.getMapper(EmployeeMapperDynamicSQL.class);
            List<Employee> emps = new ArrayList<Employee>();
            emps.add(new Employee(null, "smith", "smith@qq.com", "1"));
            emps.add(new Employee(null, "allen", "allen@qq.com", "0"));
            mapper.addEmps(emps);
            sqlSession.commit();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

5.两个内置参数

不只是方法传递过来的参数可以被用来判断,取值…
mybatis默认还有两个内置参数:

  1. _parameter:代表整个参数
    单个参数:_parameter就是这个参数
    多个参数:参数会被封装为一个map,_parameter就是代表这个map

  2. _databaseId:如果配置了databaseIdProvider标签
    _databaseId就是代表当前数据库的别名

    这个前面已经介绍过了

bind 可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值

    <select id="getEmpsTestInnerParameter" resultType="Bean.Employee">
        <bind name="_lastName" value="'%'+lastName+'%'"></bind>
        <if test="_databaseId=='mysql'">
            select * from tbl_employee
            <if test="_parameter!=null">
                where last_name like #{_lastName}
            </if>
        </if>
        <if test="_databaseId=='oracle'">
            select * from tbl_employee
        </if>
    </select>
@Test
    public void testInnerParam() {
        try {
            InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            EmployeeMapperDynamicSQL mapper = sqlSession.getMapper(EmployeeMapperDynamicSQL.class);
            Employee employee = new Employee();
            employee.setLastName("e");
            List<Employee> list = mapper.getEmpsTestInnerParameter(employee);
            for (Employee employee1 : list){
                System.out.println(employee1);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

运行结果:
在这里插入图片描述

6.sql 标签和include标签

抽取可重用的sql片段,方便后面引用
1.sql抽取,经常将要查询的列名,或者插入用的列名抽取出来方便引用
2.include来引用已经抽取的sql
3.include还可以自定义一些property,sql标签内部就能使用自定义的属性

    <sql id="insertColumn">
        last_name, email, gender
    </sql>

7.set标签

修改员工表:

<update id="updateEmp">
        update tbl_employee
        <set>
            <if test="lastName!=null">
                last_name=#{lastName},
            </if>
            <if test="email!=null">
                email=#{email},
            </if>
            <if test="gender!=null">
                gender=#{gender}
            </if>
        </set>
        where id=#{id}
    </update>
@Test
    public void testDynamicSQL06() {
        try {
            InputStream resource = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            EmployeeMapperDynamicSQL mapper = sqlSession.getMapper(EmployeeMapperDynamicSQL.class);
            Employee employee = new Employee(17, "Tony", null, null);
            mapper.updateEmp(employee);
            sqlSession.commit();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

运行结果:
在这里插入图片描述

动态SQL总结:
其实动态 sql 语句的编写往往就是一个拼接的问题,为了保证拼接准确,我们最好首先要写原生的 sql 语句出来,然后在通过 mybatis 动态sql 对照着改,防止出错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值