foreword
Recently, when developing a project, complex dynamic conditional queries are involved, but mybaits
it does not support i f elseif
-like judgments, but we can indirectly chose when otherwise
implement them choose
as a whole, which when
is if otherwise
or else
quick use
In the past, when we judged conditions, we used if
labels 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 otherwise
as long as one of the usage conditions is established, the others will not be judged. If no conditions are met, otherwise
the 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 choose
the 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中when
otherwise
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.
MyBatis
The middle <sql>
element is used to define a SQL
fragment, which is used to separate some common SQL statements, for example: SELECT
keywords and WHERE
the 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 OGNL
the 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:
SQL
in the dynamic expression${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.
${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.
MyBatis
When processing in , ${}
just use OGNL
the 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 contains
judge
<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>