关于mybatis if else if 条件判断SQL片段表达式取值和拼接问题

作者:kenx 时间:2023-02-04 18:51:21 

前言

最近在开发项目的时候涉及到复杂的动态条件查询,但是mybaits本身不支持if elseif类似的判断但是我们可以间接通过 chose when otherwise 去实现其中choose为一个整体 when是if otherwise是else

快速使用

以前我们进行条件判断时候使用if标签进行判断,条件并列存在


<if test="seat_no != null and seat_no != '' ">  
       AND seat_no = #{seat_no}  
   </if>

现在 使用chose when otherwise条件只要有一个成立,其他的就不会再判断了。如果没有成立的条件则默认执行otherwise中的内容


<choose>
   <when test="……">
   ……
   </when>
   <otherwise>
   ……
   </otherwise>
   </choose>

以下是我自己真实使用的例子,并且经过了测试,仅供参考:

根据动态条件筛选查询用户信息


<select id="findUsersByUser" resultType="cn.soboys.kmall.sys.entity.User">
       select tu.USER_ID,tu.USERNAME,tu.SSEX,td.DEPT_NAME,tu.MOBILE,tu.EMAIL,tu.STATUS,tu.CREATE_TIME,
       td.DEPT_ID
       from t_user tu left join t_dept td on tu.DEPT_ID = td.DEPT_ID

<where>
           <choose>
               <when test="userParams.adminType==4">
                   and tu.ADMIN_TYPE_ID in(2,3)
               </when>
               <otherwise>
                      <include refid="search"></include>
               </otherwise>
           </choose>

</where>

</select>
<sql id="search">
        <if test="userParams.adminType==null or userParams.adminType==''">
            and tu.ADMIN_TYPE_ID in(0,1)
        </if>

<if test="userParams.adminType != null and userParams.adminType != ''">
            and tu.ADMIN_TYPE_ID=#{userParams.adminType}
        </if>

<if test="userParams.roleId != null and userParams.roleId != ''">
            and (select group_concat(ur.ROLE_ID)
            from t_user u
            right join t_user_role ur on ur.USER_ID = u.USER_ID,
            t_role r
            where r.ROLE_ID = ur.ROLE_ID
            and u.USER_ID = tu.USER_ID and r.ROLE_ID=#{userParams.roleId})
        </if>

<if test="userParams.mobile != null and userParams.mobile != ''">
            AND tu.MOBILE =#{userParams.mobile}
        </if>
        <if test="userParams.username != null and userParams.username != ''">
            AND tu.USERNAME   like CONCAT('%',#{userParams.username},'%')
        </if>
        <if test="userParams.ssex != null and userParams.ssex != ''">
            AND tu.SSEX  =#{userParams.ssex}
        </if>
        <if test="userParams.status != null and userParams.status != ''">
            AND tu.STATUS =#{userParams.status}
        </if>
        <if test="userParams.deptId != null and userParams.deptId != ''">
            AND td.DEPT_ID =#{userParams.deptId}
        </if>
        <if test="userParams.createTime != null and userParams.createTime != ''">
            AND DATE_FORMAT(tu.CREATE_TIME,'%Y%m%d') BETWEEN substring_index(#{userParams.createTime},'#',1) and substring_index(#{userParams.createTime},'#',-1)
        </if>
    </sql>

这里就用到啦 if else if 判断。 choose标签中when条件一但不成立,就会执行otherwise标签中的条件,判断语句,也就是我下面包含的sql片段条件

更详细的条件标签使用参考我这一篇文章点击进入

SQL片段拼接

我们再写sql语句的时候往往会有这样一些要求,一些重复的sql语句片段,我们不想重复去写,那么可以通过sql片段方式去抽离,公共sql然后在需要的地方去引用

MyBatis<sql> 元素用于定义一个 SQL 片段,用于分离一些公共的 SQL 语句,例如:SELECT 关键字和 WHERE 关键字之间的部分。其中:

id:唯一标识符,用于在其他地方使用 <include> 标签引用;

lang:设置字符编码;

databaseId:指定执行该 SQL 语句的数据库ID,数据库ID在 mybatis-cfg.xml 中的中配置。

同时,你也能够看见 <sql> 标签中可以使用<include>、<trim>、<where>、<set>、<foreach>、<choose>、<if>、<bind>等标签定义复杂的 SQL 片段

简单使用定义sql片段如下:


<sql id="user_columns">
   `user_id`, `name`, `sex`, `age`
</sql>

<sql> 标签中使用 <include> 标签引入定义的sql片段,如下:


<!-- 定义基础列 -->
<sql id="user_base_columns">
   `user_id`, `name`
</sql>

<!-- 定义一个SQL片段 -->
<sql id="user_columns">
   <include refid="user_base_columns"/>, `sex`, `age`
</sql>

场景使用案例如:查询用户信息


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hxstrive.mybatis.sql.demo1.UserMapper">
  <!-- 映射结果 -->
  <resultMap id="RESULT_MAP" type="com.hxstrive.mybatis.sql.demo1.UserBean">
     <id column="user_id" jdbcType="INTEGER" property="userId" />
     <result column="name" jdbcType="VARCHAR" property="name" />
     <result column="sex" jdbcType="VARCHAR" property="sex" />
     <result column="age" jdbcType="INTEGER" property="age" />
  </resultMap>

<!-- 定义一个SQL片段 -->
  <sql id="user_columns">
     `user_id`, `name`, `sex`, `age`
  </sql>

<!-- 查询所有用户信息 -->
  <select id="findAll" resultMap="RESULT_MAP">
     select <include refid="user_columns" /> from `user`
  </select>

</mapper>

SQL参数取值和OGNL表达式

看到我们上面去值参数通过#{params}这种方式来去值的其中传进来的参数 #{xx} 就是使用的 OGNL 表达式。

Mybatis 官方文档中「XML 映射文件」模块里边,有解析到:

说当我们使用 #{} 类型参数符号的时候,其实就是告诉 Mybatis 创建一个预处理语句参数,通过 JDBC,这样的一个参数在 SQL 中会由一个 "?" 来标识,并传递到一个新的预处理语句中。

关于mybatis if else if 条件判断SQL片段表达式取值和拼接问题

也就是说当我们使用 #{XX} OGNL 表达式的时候, 它会先帮我们生成一条带占位符的 SQL 语句,然后在底层帮我们设置这个参数:ps.setInt(1, id);

OGNL 是 Object-Graph Navigation Language 的缩写,对象-图行导航语言,语法为:#{ }。
是不是有点懵,不知道这是个啥?
OGNL 作用是在对象和视图之间做数据的交互,可以存取对象的属性和调用对象的方法,通过表达式可以迭代出整个对象的结构图

MyBatis常用OGNL表达式如下:

关于mybatis if else if 条件判断SQL片段表达式取值和拼接问题

上述内容只是合适在MyBatis中使用的OGNL表达式,完整的表达式点击这里。

MyBatis中可以使用OGNL的地方有两处:

  • 动态SQL表达式中

  • ${param}参数中

如下例子MySql like 查询:


<select id="xxx" ...>
   select id,name,... from country
   <where>
       <if test="name != null and name != ''">
           name like concat('%', #{name}, '%')
       </if>
   </where>
</select>

上面代码中test的值会使用OGNL计算结果。

例二,通用 like 查询:


<select id="xxx" ...>
   select id,name,... from country
   <bind name="nameLike" value="'%' + name + '%'"/>
   <where>
       <if test="name != null and name != ''">
           name like #{nameLike}
       </if>
   </where>
</select>

这里的value值会使用OGNL计算。

注:对<bind参数的调用可以通过#{}或 ${} 方式获取,#{}可以防止注入。

在通用Mapper中支持一种UUID的主键,在通用Mapper中的实现就是使用了标签,这个标签调用了一个静态方法,大概方法如下:


<bind name="username_bind"
     value='@java.util.UUID@randomUUID().toString().replace("-", "")' />

这种方式虽然能自动调用静态方法,但是没法回写对应的属性值,因此使用时需要注意。

${params}中的参数

上面like的例子中使用下面这种方式最简单


<select id="xxx" ...>
   select id,name,... from country
   <where>
       <if test="name != null and name != ''">
           name like '${'%' + name + '%'}'
       </if>
   </where>
</select>

这里注意写的是${'%' + name + '%'},而不是%${name}%,这两种方式的结果一样,但是处理过程不一样。

MyBatis中处理${}的时候,只是使用OGNL计算这个结果值,然后替换SQL中对应的${xxx},OGNL处理的只是${这里的表达式}。

这里表达式可以是OGNL支持的所有表达式,可以写的很复杂,可以调用静态方法返回值,也可以调用静态的属性值。

例子,条件判断入参属性值是否包含子字符串可以直接使用 contains判断


<foreach collection="list" item="item" index="index" separator="AND" open="(" close=")">

<choose>
       <when test='item.cname.contains("select") or item.cname.contains("checkbox") or item.cname.contains("date")'>
           <if test='item.cname.contains("select") or item.cname.contains("checkbox")'>
               find_in_set(#{item.value},base.${item.cname})
           </if>

<if test='item.cname.contains("date")'>
               DATE_FORMAT(base.${item.cname},'%Y-%m-%d') = DATE_FORMAT(#{item.value},'%Y-%m-%d')
           </if>
       </when>
       <otherwise>
           base.${item.cname} = #{item.value}
       </otherwise>
   </choose>
</foreach>

来源:https://www.cnblogs.com/kenx/p/15336949.html

标签:mybatis,if,else,if,条件判断
0
投稿

猜你喜欢

  • Java全面细致讲解类与对象

    2022-07-07 07:04:42
  • Flutter实现微信朋友圈功能

    2022-10-02 00:28:15
  • c#实现最简洁的快速排序(你绝对可以看懂)

    2022-04-01 22:35:48
  • Android自定义View仿大众点评星星评分控件

    2023-07-22 22:37:28
  • C#四舍五入用法实例

    2021-07-20 02:49:20
  • 零基础写Java知乎爬虫之获取知乎编辑推荐内容

    2023-11-29 04:33:39
  • PowerManagerService之手动灭屏流程示例分析

    2023-01-13 17:11:51
  • 深度解析Java中ArrayList的使用

    2023-06-16 23:26:01
  • 深入了解c# 迭代器和列举器

    2022-04-24 16:32:37
  • 基于SpringBoot生成二维码的几种实现方式

    2022-02-27 16:24:31
  • C# 中用 Sqlparameter 的两种用法

    2022-11-19 03:52:52
  • Java结构型设计模式中建造者模式示例详解

    2023-04-24 13:37:31
  • Java数组越界问题实例解析

    2023-10-25 18:16:23
  • 浅谈Spring-cloud 之 sleuth 服务链路跟踪

    2022-09-24 16:07:43
  • springboot无法从静态上下文中引用非静态变量的解决方法

    2022-03-05 16:50:05
  • Java判断所给年份是平年还是闰年

    2023-10-21 17:48:59
  • C++ 关于MFC多线程编程的注意事项

    2023-02-17 22:34:44
  • C#获取远程XML文档的方法

    2023-06-26 17:41:16
  • Java 多线程并发ReentrantLock

    2022-02-23 11:53:23
  • Android实现页面短信验证功能

    2022-02-13 01:36:56
  • asp之家 软件编程 m.aspxhome.com