Mybatis的动态SQL实现
一、动态SQL简介
MyBatis的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦。拼接的时候要确保不能忘了必要的空格,还要注意省掉列名列表最后的逗号。有些时候,SQL语句where条件中,需要一些安全判断,例如按某一条件查询时如果传入的参数是空,此时查询出的结果很可能是空的,也许我们需要参数为空时,是查出全部的信息。使用Oracle的序列、mySQL的函数生成Id。这时我们可以使用动态SQL。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。通常使用动态
SQL 不可能是独立的一部分,MyBatis 当然使用一种强大的动态 SQL 语言来改进这种情形,这种语言可以被用在任意的 SQL 映射语句中。动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似。MyBatis 采用功能强大的基于 OGNL 的表达式来消除其他元素。
MyBatis中用于实现动态SQL的元素主要有:
1、if和where
2、choose(when,otherwise)
3、trim
4、set
5、foreach
下面将逐一进行介绍。
二、动态SQL的元素详解
首先来介绍一下SQL片段,它可以把动态SQL的判断部分独立处理,以便其他查询进行复用。
SQL片段定义方式:
<!--
定义sql片段
id是sql片段的唯一标识,便于下面语句的引用。通常把SQL片段设计成基于单表来定义sql片段,这样话这个sql片段可重用性才高。
注意:在sql片段中不要包括 where
-->
<sql id="query_user_where"> <if > </if>
<foreach > </foreach> <!--其他语句块--> </sql>
引用SQL片段
<where>
<!-- 引用sql片段 的id,如果refid指定的id不在本mapper文件中,需要前边加namespace -->
<include refid="query_user_where"></include>
<!-- 在这里还可以引用其它的sql片段 -->
</where>
1、if和where
if就是简单的条件判断,利用if语句我们可以实现某些简单的条件选择。动态 SQL 通常要做的事情是有条件地包含 where 子句的一部分。
使用示例:
查询语句块:
<select id="findUserList" parameterType="com.kang.pojo.UserQueryVo"
resultType="com.kang.pojo.UserCustom">
SELECT * FROM USER
<!--
where可以自动去掉条件中的第一个and
-->
<where>
<include refid="query_user_where"></include>
</where>
</select>
where元素的作用是会在写入where元素的地方输出一个where,另外一个好处是你不需要考虑where元素里面的条件输出是什么样子的,MyBatis会智能的帮你处理。如果所有的条件都不满足那么MyBatis就会查出所有的记录;如果输出后是and这个单词开头的,MyBatis会把第一个单词and忽略,当然如果是or开头的,MyBatis也会把它忽略。此外,在where元素中你不需要考虑空格的问题,MyBatis会智能的帮你加上。
SQL片段:
<sql id="query_user_where">
<if test="userCustom!=null">
<if test="userCustom.sex!=null and userCustom.sex!=''">
and user.sex = #{userCustom.sex}
</if>
<if test="userCustom.username!=null and userCustom.username!=''">
and user.username LIKE '%${userCustom.username}%'
</if>
</if>
</sql>
上述配置意思非常简单,如果你提供了sex参数,那么就要满足sex!=null和sex!=''两个条件,同样如果你提供了username参数的时候,也需要满足相应的条件,之后就是返回满足这些条件的所有user,这是非常有用的一个功能,以往我们使用其他类型框架或者直接使用JDBC的时候, 如果我们要达到同样的选择效果的时候,我们就需要拼SQL语句,这是极其麻烦的,比起来,上述的动态SQL就要简单多了。
如果输入是sex=1和username=null,那么上述配置产生的SQL语句就是:
SELECT * FROM USER where user.sex = #{userCustom.sex}
而不是:
SELECT * FROM USER and user.sex = #{userCustom.sex}
因为where标签自动加入了"where"这个关键字,而且去掉了"and"这个单词,并在where的前后自动加入了空格,最终组合成相应的SQL语句。
2、choose
choose元素的作用就相当于JAVA中的switch语句,基本上跟JSTL中的choose的作用和用法是一样的,通常都是与when和otherwise搭配的。
使用示例:
<select id="findUserList" parameterType="com.kang.pojo.UserQueryVo"
resultType="com.kang.pojo.UserCustom">
SELECT * FROM USER
<choose>
<when test="userCustom.sex!=null and userCustom.sex!=''">
and user.sex = #{userCustom.sex}
</when>
<when test="userCustom.username!=null and userCustom.username!=''">
and user.username LIKE '%${userCustom.username}%'
</when>
<otherwise>
and user.id = 1
</otherwise>
</choose>
</select>
上述配置中,when元素表示当when中的条件满足的时候就输出其中的内容,跟JAVA中的switch效果差不多的是按照条件的顺序,当when中有条件满足的时候,就会跳出choose,即所有的when和otherwise条件中,只有一个会输出,当所有的条件都不满足的时候就输出otherwise中的内容。
3、trim
trim元素的主要功能是可以在自己包含的内容前加上某些前缀,也可以在其后加上某些后缀,与之对应的属性是prefix和suffix;可以把包含内容的首部某些内容覆盖,即忽略,也可以把尾部的某些内容覆盖,对应的属性是prefixOverrides和suffixOverrides;正因为trim有这样的功能,所以我们也可以非常简单的利用trim来代替where元素的功能。
使用示例:
<select id="findUserList" parameterType="com.kang.pojo.UserQueryVo"
resultType="com.kang.pojo.UserCustom">
SELECT * FROM USER
<trim prefix="where" prefixOverrides="and |or">
<if test="userCustom!=null">
<if test="userCustom.sex!=null and userCustom.sex!=''">
and user.sex = #{userCustom.sex}
</if>
<if test="userCustom.username!=null and userCustom.username!=''">
and user.username LIKE '%${userCustom.username}%'
</if>
</if>
</trim>
</select>
4、set
set元素主要是用在更新操作的时候,它的主要功能和where元素其实是差不多的,主要是在set标签包含的语句前输出一个set。如果包含的语句是以逗号结束的话将会把该逗号忽略。如果set包含的内容为空的话则会出错。有了set元素我们就可以动态的更新那些修改了的字段,而不用每次更新全部字段。
使用示例:
<update id="updateUser" parameterType="com.kang.pojo.User">
update user
<set>
<if test="username != null">
username=#{username},
</if>
<if test="birthday != null">
birthday=#{birthday},
</if>
<if test="sex != null">
sex=#{sex},
</if>
<if test="address != null">
address=#{address}
</if>
</set>
where id = #{id}
</update>
5、foreach
foreach的主要用在构建in条件中,它可以在SQL语句中迭代一个集合。foreach元素的属性主要有item,index,collection,open,separator,close。
item表示集合中每一个元素进行迭代时的别名,index指定一个名字,用于表示在迭代过程中,每次迭代到的位置,open表示该语句以什么开始,separator表示在每次进行迭代之间以什么符号作为分隔符,close表示以什么结束。
collection属性用于指定传入参数的类型。该属性是必须指定的,在不同情况下,该属性的值是不一样的,主要有一下3种情况:
如果传入的是单参数且参数类型是一个List类型的时候,collection属性值为list。
如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array。
如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map。实际上在传入参数的时候,MyBatis也是把它封装成一个Map的,List实例将会以“list”作为键,而数组实例将会以“array”作为键。这个时候collection属性值就是传入的List或array对象在封装自身的map里面中的对应key。
传入List的使用示例:
首先是查询接口:
public List<User> findUserList(List<Integer> ids);
对应xml文件中的配置:
<select id="findUserList" resultType="com.kang.pojo.UserCustom">
SELECT * FROM USER WHERE id IN
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{ids}
</foreach>
</select>
可以看到,foreach标签描述中的参数和接口中的输入参数保持一致。
具体代码使用:
//前述代码略
UserMapper userMapper = session.getMapper(UserMapper.class);
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(3);
ids.add(6);
List<user> users = userMapper.findUserList(ids);
for (User user : users)
System.out.println(user);
session.close();
传入array数组的使用示例:
接口定义:
public List<User> findUserList(int[] ids);
对应xml文件中的配置:
<select id="findUserList" resultType="com.kang.pojo.UserCustom">
SELECT * FROM USER WHERE id IN
<foreach collection="array" index="index" item="item" open="(" separator="," close=")">
#{ids}
</foreach>
</select>
具体代码使用:
//前述代码略
UserMapper userMapper = session.getMapper(UserMapper.class);
int[] ids = {1,3,6,9};
List<user> users = userMapper.findUserList(ids);
for (User user : users)
System.out.println(user);
session.close();
传入array数组的使用示例:
接口定义:
public List<User> findUserList(Map<String, Object> params);
对应xml文件中的配置:
<select id="findUserList" resultType="com.kang.pojo.UserCustom">
SELECT * FROM USER WHERE id IN
<foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
#{params}
</foreach>
</select>
具体代码使用:
//前述代码略
UserMapper userMapper = session.getMapper(UserMapper.class);
final List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(2);
ids.add(3);
ids.add(6);
ids.add(7);
ids.add(9);
Map<String, Object> params = new HashMap<String, Object>();
params.put("ids", ids);
List<user> users = userMapper.findUserList(ids);
for (User user : users)
System.out.println(user);
session.close();
Mybatis的动态SQL实现的更多相关文章
- MyBatis的动态SQL详解
MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑,本文详解mybatis的动态sql,需要的朋友可以参考下 MyBatis 的一个强大的特性之一通常是它 ...
- Mybatis解析动态sql原理分析
前言 废话不多说,直接进入文章. 我们在使用mybatis的时候,会在xml中编写sql语句. 比如这段动态sql代码: <update id="update" parame ...
- mybatis 使用动态SQL
RoleMapper.java public interface RoleMapper { public void add(Role role); public void update(Role ro ...
- MyBatis框架——动态SQL、缓存机制、逆向工程
MyBatis框架--动态SQL.缓存机制.逆向工程 一.Dynamic SQL 为什么需要动态SQL?有时候需要根据实际传入的参数来动态的拼接SQL语句.最常用的就是:where和if标签 1.参考 ...
- 使用Mybatis实现动态SQL(一)
使用Mybatis实现动态SQL 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 写在前面: *本章节适合有Mybatis基础者观看* 前置讲解 我现在写一个查询全部的 ...
- MyBatis探究-----动态SQL详解
1.if标签 接口中方法:public List<Employee> getEmpsByEmpProperties(Employee employee); XML中:where 1=1必不 ...
- mybatis中的.xml文件总结——mybatis的动态sql
resultMap resultType可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功. 如果sql查询字段名和pojo的属性名不一致,可以通过re ...
- mybatis.5.动态SQL
1.动态SQL,解决关联sql字符串的问题,mybatis的动态sql基于OGNL表达式 if语句,在DeptMapper.xml增加如下语句; <select id="selectB ...
- MyBatis的动态SQL详解-各种标签使用
MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) ...
- 利用MyBatis的动态SQL特性抽象统一SQL查询接口
1. SQL查询的统一抽象 MyBatis制动动态SQL的构造,利用动态SQL和自定义的参数Bean抽象,可以将绝大部分SQL查询抽象为一个统一接口,查询参数使用一个自定义bean继承Map,使用映射 ...
随机推荐
- Vue表单和组件
一.表单 v-model 指令在表单控件元素上创建双向数据绑定,v-model 会根据控件类型自动选取正确的方法来更新元素. <input v-model="message" ...
- 【重点突破】—— 百度地图在React单页面应用中的使用
前言:百度地图是网页中使用地图的常用第三方工具,这里结合React项目中学到的应用场景总结一些使用要点. 一.在网页中嵌入百度地图 搜百度地图开放平台,注册百度开发者账号 控制台:查看应用.创建应用( ...
- 从头认识Spring-1.7 如何通过属性注入Bean?(1)-如何通过属性向对象注入值?
这一章节我们来讨论一下如何通过属性注入Bean? 这一章节分为两部分,第一部分我们通过属性向对象注入值,第二部分我们通过属性向对象注入还有一个对象的引用. 1.如何通过属性向对象注入值? (1)dom ...
- 怪异恼人的java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream问题的解决
测试以前做的一个邮件发送类,出现以下问题: Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/m ...
- Vue笔记五
十二.过滤器(filter) 示例代码: <template> <div id="app"> {{ msg | capitalize }} </div ...
- Linux非阻塞IO(二)网络编程中非阻塞IO与IO复用模型结合
上文描述了最简易的非阻塞IO,采用的是轮询的方式,这节我们使用IO复用模型. 阻塞IO 过去我们使用IO复用与阻塞IO结合的时候,IO复用模型起到的作用是并发监听多个fd. 以简单的回射服务器 ...
- python数据类型整理
Python中常见的数据结构可以统称为容器(container).序列(如列表和元组).映射(如字典)以及集合(set)是三类主要的容器. 一.序列(列表.元组和字符串) 序列中的每个元素都有自己的编 ...
- JQuery修改对象的属性值
JQuery修改对象的属性值 用到的便是JQuery提供的attr方法,获取属性值的基本结构为:$(obj).attr("属性名"):修改属性值的结构为:$(obj).attr(& ...
- 升级滑动销毁activity,随着手势的滑动而滑动的效果
文章开头先注明本滑动销毁是对 http://blog.csdn.net/xiaanming/article/details/20934541 这篇博客的内容进行一个小小的改动 添加向左滑动打开另外一个 ...
- sqlserver 字段内容做in条件 列变成行显示
sqlserver中 字段内容做in条件用到方法:CHARINDEX(value,situation) 列变行显示用到:stuff 详情自行查找. 例子: stuff((select ','+name ...