Mybatis if else if condition to judge the value and splicing of SQL fragment expression

foreword

Recently, when developing a project, complex dynamic conditional queries are involved, but mybaitsit does not support i f elseif-like judgments, but we can indirectly chose when otherwiseimplement them chooseas a whole, which whenis if otherwiseor else

quick use

In the past, when we judged conditions, we used iflabels to judge, and the conditions existed side by side.

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

Now chose when otherwiseas long as one of the usage conditions is established, the others will not be judged. If no conditions are met, otherwisethe content in progress will be executed by default

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

The following is an example of my own real use, and it has been tested for reference only:

Filter and query user information based on dynamic conditions

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

That's where it comes in if else if. Judgment. Once choosethe label condition is not established, the condition in the label will be executed, and the judgment statement, which is the sql fragment condition I included below中whenotherwise

For more detailed condition label usage, please refer to my article, click to enter

SQL fragment splicing

When we write sql statements, we often have such requirements. We don’t want to write some repeated sql statement fragments, so we can extract them through sql fragments, and use public sql to quote where needed.

MyBatisThe middle <sql>element is used to define a SQLfragment, which is used to separate some common SQL statements, for example: SELECTkeywords and WHEREthe part between keywords. in:

id<include>: a unique identifier for tag references used elsewhere ;

lang:Set character encoding;

databaseId: Specify the database ID to execute the SQL statement, and the database ID is configured in mybatis-cfg.xml.

At the same time, you can also see that <sql>tags <include>、<trim>、<where>、<set>、<foreach>、<choose>、<if>、<bind>such as can be used to define complex SQL fragments

Simple use defines the sql fragment as follows:

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

<sql>Use the tag in the tag to <include>introduce the defined sql fragment, as follows:

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

Scenario use cases such as: query user information

<?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 parameter values ​​and OGNL expressions

See above, the parameter #{params}#{xx} passed in is OGNLthe expression used to devalue the parameter in this way.

In the "XML Mapping File" module in the official Mybatis document, it is parsed to:

When we use the #{} type parameter symbol, we actually tell Mybatis to create a prepared statement parameter. Through JDBC, such a parameter will be identified by a "?" in SQL and passed to a new prepared statement parameter. processing statement.


That is to say, when we use the #{XX} OGNL expression, it will first help us generate a SQL statement with a placeholder, and then help us set this parameter at the bottom: ps.setInt(1, id);

OGNL is the abbreviation of Object-Graph Navigation Language, Object-Graph Navigation Language, the syntax is: #{ }.
Are you a little confused, don't know what this is?
The role of OGNL is to interact with data between objects and views. It can access the properties of objects and call methods of objects. It can iterate the structure diagram of the entire object through expressions.

MyBatis commonly used OGNL expressions are as follows:

The above content is just an OGNL expression suitable for use in MyBatis, click here for the complete expression .

There are two places where OGNL can be used in MyBatis:

  1. SQLin the dynamic expression
  2. ${param}in parameters

The following example MySql like query:

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

The value of test in the above code will use OGNL to calculate the result.

Example 2, general like query:

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

The value here will be calculated using OGNL.

Note: The call to the <bind parameter can be obtained through #{} or ${}, and #{} can prevent injection.

A UUID primary key is supported in the general Mapper. The implementation in the general Mapper is to use a label. This label calls a static method. The approximate method is as follows:

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

Although this method can automatically call the static method, it cannot write back the corresponding attribute value, so you need to pay attention when using it.

  1. ${params}parameters in

In the above like example, it is easiest to use the following method

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

Note here that it is ${'%' + name + '%'},not that %${name}%,the results of these two methods are the same, but the processing process is different.

MyBatisWhen processing in , ${}just use OGNLthe calculated result value, and then replace the corresponding one in SQL ${xxx}, OGNL only handles${这里的表达式}。

The expression here can be all expressions supported by OGNL, and can be written very complicatedly. You can call static methods to return values, or call static attribute values.

For example, the condition to judge whether the input parameter attribute value contains a substring can be directly used to containsjudge

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

Guess you like

Origin blog.csdn.net/u011738045/article/details/120483615