Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的痛点问题。
使用list:get(0)
<choose>
<when test="list.size() > 0">
SELECT * FROM table WHERE id = #{list.get(0)}
</when>
</choose>
if标签相等
<if test="grade!= null and grade!= '' and grade == '3'.toString()">
where标签
当遇到多个查询条件,使用where 1=1 可以很方便的解决我们的问题,但是这样很可能会造成非常大的性能损失,因为添加了 “where 1=1 ”的过滤条件之后,数据库系统就无法使用索引等查询优化策略,数据库系统将会被迫对每行数据进行扫描(即全表扫描) 来比较此行是否满足过滤条件,当表中的数据量较大时查询速度会非常慢;此外,还会存在SQL 注入的风险。
<select id="findActiveBlogLike" resultType="Blog">
SELECT * FROM BLOG
<where>
is_delete=0
<if test="state != null and state != ''">
state = #{state}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
choose标签(IF/ELSE)
有时候我们并不想应用所有的条件,而只是想从多个选项中选择一个。choose标签是按顺序判断其内部when标签中的test条件出否成立,如果有一个成立,则 choose 结束。当 choose 中所有 when 的条件都不满则时,则执行 otherwise 中的sql。类似于Java 的 switch 语句,choose 为 switch,when 为 case,otherwise 则为 default。
<choose>
<when test="isUpdate !=null ">
AND u.is_update = #{isUpdate, jdbcType=INTEGER}
</when>
<when test="isDelete != null">
AND u.is_delete = #{isDelete, jdbcType=INTEGER}
</when>
<otherwise>
</otherwise>
</choose>
foreach标签
批量添加
假设接口中传递的list如下所示:
List<String> list = new ArrayList<>();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
Integer temp = 0;
while (temp < size) {
Long start = System.currentTimeMillis();
rptMapper.batchAllList(
resultList.subList(temp, Math.min(temp + insertMaxNum, size)));
log.info("batchAllList:{}ms,start:{},end:{}",
System.currentTimeMillis() - start, temp, Math.min(temp + insertMaxNum, size));
temp += insertMaxNum;
}
其中foreach标签配置如下
<insert id="insertMoreByList">
insert into t_emp values
<foreach collection="emps" item="emp" separator=",">
(null, #{emp.empName}, #{emp.age}, #{emp.sex}, #{emp.email}, null)
</foreach>
</insert>
<foreach collection="list" item="item" separator=",">
(#{item})
</foreach>
最终的结果为
('zhangsan'),('lisi'),('wangwu')
如果在foreach标签前面加上insert into table values,将会变形成
INSERT INTO user(user_name) VALUES('zhangsan'),('lisi'),('wangwu')
IN查询
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID IN
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
include标签
SQL片段达到代码复用
mybatis中sql标签与include标签进行配合,灵活的查询需要的数据。抽取可重用的sql片段放include,方便后面引用
<mapper namespace="com.test.BaseDAO">
<sql id="where">STATUS IN (1,2,3,4)</sql>
</mapper>
<select id="findAll" resultMap="BaseResultMap">
SELECT * FROM TEST WHERE <include refid="com.test.BaseDAO.where"/>
</select>
通过property标签动态传参
采用${}
取参数时,include
标签的property
属性的优先级要高于外围mapper
的参数;
<select id="selectById" resultMap="BaseResultMap">
select
my.*
FROM
sys_user my
<include refid="test">
<property name="testVal" value="1"/>
</include>
</select>
<sql id="test">
<if test="testVal!= null">
WHERE my.id = ${testVal}
</if>
</sql>
-- 执行结果:select my.* FROM sys_user my WHERE my.id = 1
<select id="query" resultType="User">
select
<include refid="hah">
<property name="abc" value="id"/>
</include>
from t_user
</select>
<sql id="hah">
${abc},username,password
</sql>
-- 执行结果:select id,username,password from t_user
多个Where别名不同
<select id="selectById" resultMap="BaseResultMap">
select
my.*
FROM
sys_user my
<include refid="test">
<property name="fieldPrefix" value="my."/>
</include>
</select>
-- 执行结果 select my.* FROM sys_user my WHERE my.id = 1
<select id="selectByDepartment" resultMap="BaseResultMap">
select
my.*
FROM
sys_user my
LEFT JOIN sys_department dep ON my.department_id = dep.id
<include refid="test">
<property name="fieldPrefix" value="dep."/>
</include>
</select>
/* 执行结果
select my.* FROM sys_user my
LEFT JOIN sys_department dep ON my.department_id = dep.id
WHERE dep.id = 1
*/
<sql id="test">
WHERE ${fieldPrefix}id = 1
</sql>
如果在多个xml中都要使用,则可以新建一个xml,引用时用 NAMESPACE.ID
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="base">
<sql id="test">
WHERE my.id = ${fieldPrefix}
</sql>
</mapper>
调用
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.*.*.*.*.testMapper">
<select id="selectById" resultMap="BaseResultMap">
select
my.*
FROM
sys_user my
<include refid="base.test">
<property name="testVal" value="1"/>
</include>
</select>
</mapper>
trim标签(动态拼接)
一般用于去除sql语句中多余的and关键字,逗号,或者给sql语句前拼接 “where“、“set“以及“values(“ 等前缀,或者添加“)“等后缀,可用于选择性插入、更新、删除或者条件查询等操作。
select * from user where age=#{age} and phone=#{phone}
prefixOverrides 使用
select * from user where and age = ? and phone = ?
在动态sql的查询过程中,如果age为null,所以第一个if不成立,里面的SQL语句不拼接,第二个if里面的and边紧跟在where后面了,语法错误。为了解决这个问题,只要加上prefixOverride即可,表示把动态生成的sql中,trim标签内的首个“and”去掉。
<select id="getUserList" resultType="User">
SELECT * FROM user
<trim prefix="WHERE" prefixOverrides="AND | OR">
<if test="age != null">AND age = #{age}</if>
<if test="phone != null">AND phone = #{phone}</if>
</trim>
</select>
<trim prefix="HAVING" prefixOverrides="AND">
<if test="userName !=null and userName !='' ">
AND count(userName)>1
</if>
<if test="classes !=null and classes !='' ">
AND sum(classes)>60
</if>
</trim>
suffixOverrides的使用
update user_tab set ast_name=?, age=?,
若phone的值为null,则会导致生成的sql语句最后一个符号为“,”,导致生成的sql出错。 为了避免此种情况,可使用trim标签中的suffixOverrides 将最后面的一个符号覆盖掉。
<update id="updateUser">
<trim suffix="where id=#{id}" suffixOverrides=",">
update user_tab
set
<if test="lastName != null">
last_name=#{lastName},
</if>
<if test="age != null">
age=#{age},
</if>
<if test="phone != null">
phone=#{phone}
</if>
</trim>
</update>
resultType标签
返回值为简单类型
resultType="java.lang.Integer"
<select id = "selectMaxAgeBySex" resultType="java.lang.Integer">
select max(age) from user where sex = '女'
</select>
返回值为Map类型
将列名作为键,将查询出来的数据结果作为值。大概的应用场景是不知道查询的结果有多少字段或者不清楚字段名称。
<!--public List<Map<String,Object>> getMyUser()-->
<select id="getMyUser" resultType="map">
select * from myuser
</select>
多条记录
一条记录
<select id="selectMyUserById" resultType="map" parameterType="integer">
select * from myuser where id = #{id}
</select>
还有一种使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功,这种不描叙了。
update标签
当 MyBatis 执行完一条更新语句后,会返回一个整数,返回值为受影响的数据库记录的行。update标签没有resultType属性
<!--update 标签-->
<update id="updateUserInfo" parameterType="string">
update UserInfo set name = #{name}
</update>
set标签
可以动态更新需要更新的列,忽略其它不更新的列,例:
<update id="updateUserInfo" parameterType="map">
update user_info
<set>
<if test="userName!= null and userName!=''">
userName=#{userName},
</if>
userSex=#{userSex}
</set>
where id=#{keyId}
</update>
在 UserInfoMapper 接口中增加一个 updateUserInfo() 方法,代码如下。
int updateUserInfo(String name);
delete标签
delete 标签用于定义 delete 语句,执行删除操作。当 MyBatis 执行完一条更新语句后,会返回一个整数,表示受影响的数据库记录的行数。