目录
一 简介
MyBatis提供了强大的动态sql功能,使用起来非常方便。在MyBtais3之前的版本,动态SQL较为复杂。现在采用了OGNL,已经非常方便了。
二 if
一般用于where条件中,也可以是update或insert
2.1 where中使用if
接口方法
/**
* 在where中使用if
* @param sysUser
* @return
*/
List<SysUser> selectByUser(SysUser sysUser);
映射语句
这时需要添加where 1=1
,否则有些场景可能会报错
<select id="selectByUser" resultType="zyc.mybatis.simple.model.SysUser">
select id,
user_name userName,
user_password userPassword,
user_email userEmail,
user_info userInfo,
head_img headImg,
create_time createTime
from sys_user
where 1=1
<if test="@org.apache.commons.lang3.StringUtils@isNotEmpty(userName)">
and user_name like concat('%', #{userName}, '%')
</if>
<if test="userEmail != '' and userEmail != null">
and user_email = #{userEmail}
</if>
</select>
2.2 update更新列中使用if
需求:
只更新有值的字段。一般选择性更新都是以Selective作为后缀
接口方法
/**
* 根据主键更新
* 子啊update时使用if
*
* @param sysUser
* @return
*/
int updateByIdSelective(SysUser sysUser);
映射语句
<update id="updateByIdSelective">
update sys_user
set
<if test="userName != null and userName != ''">
user_name = #{userName},
</if>
<if test="userPassword != null and userPassword != ''">
user_password = #{userPassword},
</if>
<if test="userEmail != null and userEmail != ''">
user_email = #{userEmail},
</if>
<if test="userInfo != null and userInfo != ''">
user_info = #{userInfo},
</if>
<if test="headImg != null">
head_img = #{headImg, jdbcType=BLOB},
</if>
<if test="createTime != null">
create_time = #{createTime, jdbcType=TIMESTAMP},
</if>
id = #{id}
where id = #{id}
</update>
2.3 insert时动态插入
接口方法
/**
* 动态插入
* @param sysUser
* @return
*/
int insertSelective(SysUser sysUser);
映射sql
<insert id="insertSelective" useGeneratedKeys="true" keyProperty="id">
insert into sys_user(
user_name, user_password,
<if test="userEmail != null">
<if test="userEmail != ''">
user_email,
</if>
</if>
user_info, head_img, create_time)
values(
#{userName}, #{userPassword},
<if test="userEmail != null">
<if test="userEmail != ''">
#{userEmail},
</if>
</if>
#{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP})
</insert>
三 choose
该标签能够实现if..else if...else
的逻辑。(注意多个when是顺序判断的,只要有一个满足了,后面就不会生效。就是java的if ..else语法
)
choose标签需要和when和otherwise两个标签配合使用
。一个choose中至少有一个
when,有0个或者1个
otherwise。
接口方法
/**
* 根据用户 id 或用户名查询
* choose标签
* @param sysUser
* @return
*/
SysUser selectByIdOrUserName(SysUser sysUser);
映射sql
这里的limit 0
也是个技巧
<select id="selectByIdOrUserName" resultType="zyc.mybatis.simple.model.SysUser">
select id,
user_name userName,
user_password userPassword,
user_email userEmail,
user_info userInfo,
head_img headImg,
create_time createTime
from sys_user
where 1 = 1
<choose>
<when test="id != null">
and id = #{id}
</when>
<when test="userName != null and userName != ''">
and user_name = #{userName}
</when>
<otherwise>
limit 0
</otherwise>
</choose>
</select>
四 where、set、trim
这3个标签功能很像,实际上where和set就是trim的一种用法
4.1 where
前面我们在where中使用if,还需要写 where 1=1
,这样太麻烦而且不够优雅。
作用
如果该标签包含的元素中有返回值,就插入一个where ;如果where后面的字符串是以AND 和OR 开头的,就将它们剔除。
我们修改上面的selectByUser映射语句
<select id="selectByUser" resultType="zyc.mybatis.simple.model.SysUser">
select id,
user_name userName,
user_password userPassword,
user_email userEmail,
user_info userInfo,
head_img headImg,
create_time createTime
from sys_user
<where>
<if test="@org.apache.commons.lang3.StringUtils@isNotEmpty(userName)">
and user_name like concat('%', #{userName}, '%')
</if>
<if test="userEmail != '' and userEmail != null">
and user_email = #{userEmail}
</if>
</where>
</select>
4.2 set用法
用法
如果该标签包含的元素中有返回值,就插入一个set
:如果set 后面的字符串是以逗号结尾的,就将这个逗号剔除
。
修改上面的updateByIdSelective方法
<update id="updateByIdSelective">
update sys_user
<set>
<if test="userName != null and userName != ''">
user_name = #{userName},
</if>
<if test="userPassword != null and userPassword != ''">
user_password = #{userPassword},
</if>
<if test="userEmail != null and userEmail != ''">
user_email = #{userEmail},
</if>
<if test="userInfo != null and userInfo != ''">
user_info = #{userInfo},
</if>
<if test="headImg != null">
head_img = #{headImg, jdbcType=BLOB},
</if>
<if test="createTime != null">
create_time = #{createTime, jdbcType=TIMESTAMP},
</if>
id = #{id},
</set>
where id = #{id}
</update>
4.3 trim 用法
trim的功能最强大,where、set都可以用trim实现
trim标签的属性
- prefix :当trim 元素内包含内容时,会给内容增加prefix 指定的前缀。
- prefixOverrides :当trim 元素内包含内容时,会把内容中匹配的前缀字符串去掉。
- suffix :当trim 元素内包含内容时,会给内容增加suffix 指定的后缀。
- suffixOverrides :当trim 元素内包含内容时,会把内容中匹配的后缀字符串去掉。
如,用trim实现where
这里的and和or后的空格也和关键,这样表明是一个独立的单词,不会和order等字段名匹配。实际的prefixOverrides更复杂,还需要处理各种空白字符,这里只是简化!
<trim prefix="where" prefixOverrides="and |or ">
...
</trim>
五 foreach
我们经常会使用in查询,这时foreach可以方便地实现需求。
foreach 可以对数组、Map 或实现了工terable 接口(如List 、Set )的对象进行遍历。数组在处理时会转换为List 对象,因此foreach 遍历的对象可以分为两大类:Iterable类型和Map 类型
5.1 实现in集合
接口方法
/**
* 根据用户 id 集合查询
* foreach用法
* @param idList
* @return
*/
List<SysUser> selectByIdList(List<Long> idList);
映射sql
<select id="selectByIdList" resultType="zyc.mybatis.simple.model.SysUser">
select id,
user_name userName,
user_password userPassword,
user_email userEmail,
user_info userInfo,
head_img headImg,
create_time createTime
from sys_user
where id in
<foreach collection="list" open="(" close=")" separator="," item="id" index="i">
#{id}
</foreach>
</select>
5.2 标签属性
- collection :必填,
值为要选代循环的属性名
。这个属性值的情况有很多。 - item:变量名,值为从法代对象中取出的每一个值。
- index :索引的属性名,在集合数组情况下值为当前索引值,当选代循环的对象是Map类型时,这个值为Map 的key (键值)。
- open:整个循环内容开头的字符串。
- close :整个循环内容结尾的字符串。
- separator :每次循环的分隔符
5.3 collection的属性设置规则
只有一个参数时
- 集合用collection,List可以用list(
就像上面,这两者都可以
) - 数组用array
- 推荐使用@Param 来指定参数的名字,这时可以设置成我们自定义地名字
- 可以使用默认值
_parameter
方法有多个参数时
在笔记2中提过,推荐使用@Param来指定名字
5.4 实现批量插入
首先要实现批量插入,对应的数据库必须支持。我们下面会以MySQL为例(MySQL支持这种语法
)
接口方法
/**
* 批量插入用户信息
*
* @param userList
* @return
*/
int insertList(List<SysUser> userList);
对应sql
<insert id="insertList" useGeneratedKeys="true" keyProperty="id">
insert into sys_user(
user_name, user_password,user_email,
user_info, head_img, create_time)
values
<foreach collection="list" item="user" separator=",">
(
#{user.userName}, #{user.userPassword},#{user.userEmail},
#{user.userInfo}, #{user.headImg, jdbcType=BLOB}, #{user.createTime, jdbcType=TIMESTAMP})
</foreach>
</insert>
从MyBatis 3.3. 1版本开始,MyBatis 开始支持批量新增回写主键值的功
这个功能首先要求数据库主键值为自增类型
,同时还要求该数据库提供的JDBC 驱动可以支持返回批量插入
的主键值(JDBC 提供了接口,但并不是所有数据库都完美实现了该接口,MySQL完美支持)所以应用场景不多,我个人觉得主键最好还是自己设置比较好
用法就是和普通插入一样useGeneratedKeys="true" keyProperty="id"
5.5 动态update
接口方法
/**
* 通过 Map 更新列
*
* @param map
* @return
*/
int updateByMap(Map<String, Object> map);
int updateByMap2(@Param("m1") Map<String, Object> map);//测试@Param效果
映射语句
<update id="updateByMap">
update sys_user
set
<foreach collection="_parameter" item="val" index="key" separator=",">
${key} = #{val}
</foreach>
where id = #{id}
</update>
<update id="updateByMap2">
update sys_user
set
<foreach collection="m1" item="val" index="key" separator=",">
${key} = #{val}
</foreach>
where id = #{m1.id}
</update>
六 bind
bind 标签可以使用OGNL 表达式创建一个变量并将其绑定到上下文中
。
如
<bind name="userNameLike" value="'%'+userName+'%'"/>
七 多数据支持
具体没试,记录几个重点
- 匹配规则:DB VENDOR 的匹配策略为DatabaseMetaData#getDatabaseProductName ()返
回的字符串包含property 中name 部分的值即可匹配
- 很多标签都有databaseId属性。可以指定对应的数据库类型,也可以不指定。
- MyBatis 会加载
不带databaseId 属性和带有匹配当前数据库databaseld 属性
的所有语句。如果同时找到带有databaseId 和不带databaseId的相同语句,则后者会被舍弃
。 - 实现多数据支持。
可以写两条sql,也可以使用if标签实现局部更换