MyBatis learning - Dynamic SQL

  When developers use JDBC framework or other similar database development framework, based on demand usually have to go hand stitching SQL, this is very troublesome, and myBatis provides dynamic SQL statements assembly function, just to solve this problem.

First, the dynamic SQL elements

  Dynamic SQL is one of the powerful features of MyBatis, MyBatis 3 uses OGNL based expressions to complete dynamic SQL,

  MyBatis dynamic SQL in the main elements, as follows:

element Explanation
<if> Analyzing statements, conditional branching is determined for single
<choose>(<when>,<otherwise>) Java equivalent of switch..case ... default
<where>,<trim>,<set> Subsidy element, used to treat some SQL stitching, special character problem
<foreach> Loop, commonly used in the conditions mentioned in the statement, etc.
<bind> Creating a variable from OGNL expression, and bind it to the context, commonly used in the fuzzy query in sql

 

two.

1. <if> element: typically used to accurately query a plurality of data conditions

  With MyBatis, <if> element is the most common decision statement, which is similar to the if statement in Java, mainly for simple conditional judgment.

  (1) using the <if> element in the mapping file to write according to the customer name and customer portfolio career information to query customer information.

<!-- 使用if元素来进行查询 -->
    <select id="findCustomerByNameAndJobs" parameterType="com.itheima.po.Customer" 
                                          resultType="com.itheima.po.Customer">
        select * from t_customer where 1=1
        <if test="username != null and username !='' ">
            and username like concat('%',#{username},'%')
        </if>
        <if test="jobs != null and jobs !='' ">
            and jobs=#{jobs}
        </if>                                      
    </select>

  Use <if> test element attributes username and jobs have been determined non-empty (test attributes used in the determination conditions for determining true and false, most of the time is used for determination of non-null), if the incoming non conditions empty, were sql stitching.

  (2) in the test class, write test method findCustomerByNameAndJobs:

/ ** 
     * The user name and the user's work to query the user 
     * / 
    @Test 
    public  void findCustomerByNameAndJobsTest () {
         // generated by tools The SqlSession 
        SqlSession SQLSESSION = MyBatisUtils.getSession ();
         // create a Customer object, the package need to be combined query conditions 
        the Customer = Customer new new the Customer (); 
        customer.setJobs ( "Teacher" ); 
        customer.setUsername ( "Jack" ); 
        
        // query method performed SqlSession object returns a result set 
        List <Customer> customers = sqlSession. selectList ( "com.itheima.mapper.CustomerMapper.findCustomerByNameAndJobs" , the Customer);
         //Output Results 
        for (the Customer Customer2: the Customers) { 
            System.out.println (Customer2); 
        } 
        
        // close SQLSESSION 
        sqlSession.close (); 
    }

  (3) Test Results:

   

 

 

  (4) If the value set in the code above commented below, all information will be output: 

1      / * 
2       * The user name and the user's work to a user query
 . 3       * / 
. 4      @Test
 . 5      public  void findCustomerByNameAndJobsTest () {
 . 6          // generates The SqlSession by tools 
. 7          SqlSession SQLSESSION = MyBatisUtils.getSession ();
 . 8          / / create a Customer object, encapsulating the query need to be combined 
. 9          Customer = Customer new new Customer ();
 10          // customer.setJobs ( "Teacher");
 . 11          // customer.setUsername ( "Jack");
 12 is          
13 is          // performed SqlSession the method of the query object and returns a result set 
14         List<Customer> customers=sqlSession.selectList("com.itheima.mapper.CustomerMapper.findCustomerByNameAndJobs", customer);
15         //输出查询结果
16         for(Customer customer2:customers) {
17             System.out.println(customer2);
18         }
19         
20         //关闭sqlSession
21         sqlSession.close();
22     }

 

     

      

 

 

 

 2. <choose>, <when>, <otherwise>: to perform a select from multiple options

  In the <if>, as long as the conditions of the test attribute is true, went to perform conditional statement elements, but in real life is sometimes required to perform a select from several options, such as

  When a customer name can not be empty, only for customer screening based on customer name,

  When the customer name is empty, occupation is not empty on client-screening based on customer occupation,

  If both are empty, then check out all the phone is not empty customer information

  In this case, can not be used <if> element, for the situation described above, may be used <choose>, <when>, <otherwise> element where a combination of the above

  (1) Configuration In the following mapping file

<!-- <choose>(<when>,<otherwise>元素的组合使用) -->
    <select id="findCustomerByNameOrJobs" parameterType="com.itheima.po.Customer" 
                                          resultType="com.itheima.po.Customer">
        select * from t_customer where 1=1
        <choose>
        
            <when test="username != null and username != '' ">
                and username like concat('%',#{username},'%')
            </when>
            <when test="jobs != null and jobs !='' ">
                and jobs=#{jobs}
            </when>
            <otherwise>
                and phone is not null
            </otherwise>
            
        </choose>
    </select>

 

  在上述代码中,使用了<choose>,<when>,<otherwise>组合,当第一个<when>元素中的条件为真时,则只动态地组装第一个<when>元素中的条件,否则就继续向下判断第二个<when>元素中的条件是否为真,依次类推,如果<when>中的条件都不为真时,就会执行<otherwise>内的SQL片段。

  (2)创建测试方法

/**
     * 根据用户名或者职业来查询用户信息
     */
    @Test
    public void findCustomerByNameOrJobs() {
        //通过工具类来生成SqlSession对象
        SqlSession sqlSession=MyBatisUtils.getSession();
        //创建Customer对象,封装需要组合查询的条件
        Customer customer=new Customer();
        customer.setJobs("teacher");
        customer.setUsername("jack");
        
        //执行SqlSession对象的查询方法,返回一个结果集
        List<Customer> customers=sqlSession.selectList("com.itheima.mapper.CustomerMapper.findCustomerByNameOrJobs", customer);
        //输出查询结果
        for(Customer customer2:customers) {
            System.out.println(customer2);
        }
        
        //关闭sqlSession
        sqlSession.close();
    }

 

  (3)测试结果

       

  (4)当把customer.setUsername("jack")注释掉后,结果为:

        

  (5)如果把customer.setJobs(“teacher”)也注释掉后,结果为:

       

  

 

 

 

3.<where>,<trim>元素

  在前面的小节中编写的SQL后面都添加了“where 1=1 "这个条件,那么为什么要这么写呢?是应为如果将后面的”where 1=1“去掉,那么MyBatis拼接出来的SQL语句将会出错

  SELECT *from t_customer  where and usename like  concat( '%',#{username}, '%');

  在上面的语句中,where后面跟的是and,这样将出错,而加入了where 1=1 后,既保证了where后面的条件成立,也保证了避免where后面跟着是and或者or.

那么在Mybatis中有什么办法是可以不加入”1=1“这个条件也可以呢?

  MyBatis提供了<where>元素来处理这样的问题。例如

   <select id="findCustomerByNameAndJobs" parameterType="com.itheima.po.Customer" 
                                          resultType="com.itheima.po.Customer">
        select * from t_customer 
     <where> <if test="username != null and username !='' "> and username like concat('%',#{username},'%') </if> <if test="jobs != null and jobs !='' "> and jobs=#{jobs} </if>
    </where> </select>

 

  在上面的语句中,使用<where>元素取代了”where 1=1“, where元素会自动判断组合条件下的拼接的sql语句,只有当<where>里的条件成立时,才会在拼接sql时,加入where元素,否则不会添加,即使where后面有多余的"and",“or”,<where>元素会自动将它们除去。

 

4.<set>元素

  在Hibernate中,如果要更新一条数据,就需要发送所有的字段给持久化对象,然而在实际应用中,大多数情况下,是只跟新某一个字段或者几个字段,如果更新的每一条数据都要将所有的属性都更新一遍,那么其执行效率是非常的低,有没有办法使程序只更新需要更新的字段?

  在MyBatis中,提供了<set>元素来完成这一工作,<set>元素的作用用于更新操作,其主要作用是在动态包含的SQL语句前输出一个SET关键字,并且将SQL语句中最后一个多余的逗号去除。

  例如,在入门案例中,使用<set>元素对更新操作的代码进行修改如下:

<!-- set元素的使用 -->
    <update id="updateCustomer" parameterType="com.itheima.po.Customer">
    
        update t_customer
        <set>
            <if test="username != null and username !='' ">
                username=#{username},
            </if>
            <if test="jobs != null and jobs != ''">
                jobs=#{jobs},
            </if>
            <if test ="phone != null and phone != ''">
                phone=#{phone},
            </if>
        </set>
        where id=#{id}
        
    </update>

 

   在上面的sql语句中,使用了<set>和<if>语句相组合的方法将组装update语句,其中<set>元素会自动的动态前置SET关键字,同时也会消除sql语句的最后一个多余的逗号,<if>元素是用来判断相应的字段是否传入值,如果传入的更新字段非空,就将此字段进行动态的组装,并且更新此字段,否则此字段不更新。

  在测试类中编写如下代码:

    /**
     *使用set 更新客户
     */
    @Test
    public void updateCustomer1Test() {
        //1.通过工具类来生成SqlSession对象
        SqlSession sqlSession=MyBatisUtils.getSession();
        //2.创建Customer对象,并向对象中添加数据
        Customer customer=new Customer();
        customer.setId(3);
        customer.setPhone("444444");
        //3.执行sqlSession的更新方法,返回的是受影响的行数
        int rows=sqlSession.update("com.itheima.mapper.CustomerMapper.updateCustomer", customer);
        //4.根据返回的结果来判断是否更新成功
        if(rows>0) {
            System.out.println("更新成功!");
        }else {
            System.out.println("更新失败!");
        }
        
        //5.提交事务
        sqlSession.commit();
        //6.关闭事务
        sqlSession.close();
    }
    

  测试结果如下:

  

 

 

   注意:使用<set>和<if>元素组合进行update语句动态的SQL组装时,如果<set>中的内容都为空,则会出现sql语法错误,所以在<set>元素进行动态更新时,要确保传入的更新字段不为空。

 

 

5.<foreach>元素

   该元素是用于数组和集合循环遍历。

  <foreach>元素是通常在构建IN条件语句时使用的,其使用方法如下

 

<select id="findCustomerByIds" parameterType="List" resultType="com.itheima.po.Customer">
        select * from t_customer where id in
        <foreach item="id" index="index" collection="list" open="("  separator="," close=")">
            #{id}
        </foreach>
    </select>

 

  在上述代码中,使用了<foreach>元素对传入的集合进行了遍历并进行了动态的SQL组转,其属性如下:

  item:配置的是循环中当前的元素。

  index:配置的是当前元素在集合的位置下标。

  collection:配置的list是传递过来的参数类型(首字母小写),她可以是一个array,list(或者是collection),Map集合的建,POJO包装类中数组或者集合类型的属性名。

  open和close:配置的是以什么符号将这些集合元素包装起来。

  separate:配置的是各个元素之间的间隔符。

  在测试类中编写如下代码,验证

/**
     * 根据客户编号批量查询客户信息
     */
    @Test
    public void findCustomerByIdsTest() {
        //1.获取SqlSession对象
        SqlSession sqlSession=MyBatisUtils.getSession();
        //2.创建一个list集合,用来封装查询的id值
        List<Integer> ids=new ArrayList<Integer>();
        ids.add(2);
        ids.add(3);
        //3.执行SqlSession的查询方法,返回结果集
        List<Customer> customers=sqlSession.selectList("com.itheima.mapper.CustomerMapper.findCustomerByIds", ids);
        //4.输出查询的结果
        for(Customer customer:customers) {
            System.out.println(customer);
        }
        //5.关闭sqlSession
        sqlSession.close();
    }

  测试结果如下:

    

  注意:在使用<foreach>元素时,应注意的事项是collection属性值,该属性是必须要指定的,并且在不同的情况下,该属性的值是不同的,主要三种情况:

  (1)如果在调用该sql语句时,传入的是一个参数,并且参数的类型是一个数组或者是list的时候,该collection属性值就是array和list(或者collection)

  (2)如果传入的是多个参数的时候,就需要把它们封装成一个Map,单个参数也是可以这样封装的,这时候collection属性值就是Map的键

  (3)如果传进来的是POJO的包装类的时候,collection属性值就是该包装类中需要进行遍历的数组或者集合的属性名。

 

Guess you like

Origin www.cnblogs.com/zhilili/p/11604494.html