Java-MyBatis:MyBatis 3 动态 SQL
ylbtech-Java-MyBatis:MyBatis 3 动态 SQL |
1.返回顶部 |
动态 SQL
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
if
动态 SQL 通常要做的事情是根据条件包含 where 子句的一部分。比如:
- <select id="findActiveBlogWithTitleLike"
- resultType="Blog">
- SELECT * FROM BLOG
- WHERE state = ‘ACTIVE’
- <if test="title != null">
- AND title like #{title}
- </if>
- </select>
这条语句提供了一种可选的查找文本功能。如果没有传入“title”,那么所有处于“ACTIVE”状态的BLOG都会返回;反之若传入了“title”,那么就会对“title”一列进行模糊查找并返回 BLOG 结果(细心的读者可能会发现,“title”参数值是可以包含一些掩码或通配符的)。
如果希望通过“title”和“author”两个参数进行可选搜索该怎么办呢?首先,改变语句的名称让它更具实际意义;然后只要加入另一个条件即可。
- <select id="findActiveBlogLike"
- resultType="Blog">
- SELECT * FROM BLOG WHERE state = ‘ACTIVE’
- <if test="title != null">
- AND title like #{title}
- </if>
- <if test="author != null and author.name != null">
- AND author_name like #{author.name}
- </if>
- </select>
choose, when, otherwise
有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
还是上面的例子,但是这次变为提供了“title”就按“title”查找,提供了“author”就按“author”查找的情形,若两者都没有提供,就返回所有符合条件的 BLOG(实际情况可能是由管理员按一定策略选出 BLOG 列表,而不是返回大量无意义的随机结果)。
- <select id="findActiveBlogLike"
- resultType="Blog">
- SELECT * FROM BLOG WHERE state = ‘ACTIVE’
- <choose>
- <when test="title != null">
- AND title like #{title}
- </when>
- <when test="author != null and author.name != null">
- AND author_name like #{author.name}
- </when>
- <otherwise>
- AND featured = 1
- </otherwise>
- </choose>
- </select>
trim, where, set
前面几个例子已经合宜地解决了一个臭名昭著的动态 SQL 问题。现在回到“if”示例,这次我们将“ACTIVE = 1”也设置成动态的条件,看看会发生什么。
- <select id="findActiveBlogLike"
- resultType="Blog">
- SELECT * FROM BLOG
- WHERE
- <if test="state != null">
- state = #{state}
- </if>
- <if test="title != null">
- AND title like #{title}
- </if>
- <if test="author != null and author.name != null">
- AND author_name like #{author.name}
- </if>
- </select>
如果这些条件没有一个能匹配上会发生什么?最终这条 SQL 会变成这样:
- SELECT * FROM BLOG
- WHERE
这会导致查询失败。如果仅仅第二个条件匹配又会怎样?这条 SQL 最终会是这样:
- SELECT * FROM BLOG
- WHERE
- AND title like ‘someTitle’
这个查询也会失败。这个问题不能简单地用条件句式来解决,如果你也曾经被迫这样写过,那么你很可能从此以后都不会再写出这种语句了。
MyBatis 有一个简单的处理,这在 90% 的情况下都会有用。而在不能使用的地方,你可以自定义处理方式来令其正常工作。一处简单的修改就能达到目的:
- <select id="findActiveBlogLike"
- resultType="Blog">
- SELECT * FROM BLOG
- <where>
- <if test="state != null">
- state = #{state}
- </if>
- <if test="title != null">
- AND title like #{title}
- </if>
- <if test="author != null and author.name != null">
- AND author_name like #{author.name}
- </if>
- </where>
- </select>
where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。
如果 where 元素没有按正常套路出牌,我们可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
- <trim prefix="WHERE" prefixOverrides="AND |OR ">
- ...
- </trim>
prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 属性中的内容,并且插入 prefix 属性中指定的内容。
类似的用于动态更新语句的解决方案叫做 set。set 元素可以用于动态包含需要更新的列,而舍去其它的。比如:
- <update id="updateAuthorIfNecessary">
- update Author
- <set>
- <if test="username != null">username=#{username},</if>
- <if test="password != null">password=#{password},</if>
- <if test="email != null">email=#{email},</if>
- <if test="bio != null">bio=#{bio}</if>
- </set>
- where id=#{id}
- </update>
这里,set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号,因为用了条件语句之后很可能就会在生成的 SQL 语句的后面留下这些逗号。(译者注:因为用的是“if”元素,若最后一个“if”没有匹配上而前面的匹配上,SQL 语句的最后就会有一个逗号遗留)
若你对 set 元素等价的自定义 trim 元素的代码感兴趣,那这就是它的真面目:
- <trim prefix="SET" suffixOverrides=",">
- ...
- </trim>
注意这里我们删去的是后缀值,同时添加了前缀值。
foreach
动态 SQL 的另外一个常用的操作需求是对一个集合进行遍历,通常是在构建 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>
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及在迭代结果之间放置分隔符。这个元素是很智能的,因此它不会偶然地附加多余的分隔符。
注意 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象传递给 foreach 作为集合参数。当使用可迭代对象或者数组时,index 是当前迭代的次数,item 的值是本次迭代获取的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
到此我们已经完成了涉及 XML 配置文件和 XML 映射文件的讨论。下一章将详细探讨 Java API,这样就能提高已创建的映射文件的利用效率。
bind
bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如:
- <select id="selectBlogsLike" resultType="Blog">
- <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
- SELECT * FROM BLOG
- WHERE title LIKE #{pattern}
- </select>
多数据库支持
一个配置了“_databaseId”变量的 databaseIdProvider 可用于动态代码中,这样就可以根据不同的数据库厂商构建特定的语句。比如下面的例子:
- <insert id="insert">
- <selectKey keyProperty="id" resultType="int" order="BEFORE">
- <if test="_databaseId == 'oracle'">
- select seq_users.nextval from dual
- </if>
- <if test="_databaseId == 'db2'">
- select nextval for seq_users from sysibm.sysdummy1"
- </if>
- </selectKey>
- insert into users values (#{id}, #{name})
- </insert>
动态 SQL 中的可插拔脚本语言
MyBatis 从 3.2 开始支持可插拔脚本语言,这允许你插入一种脚本语言驱动,并基于这种语言来编写动态 SQL 查询语句。
可以通过实现以下接口来插入一种语言:
- public interface LanguageDriver {
- ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql);
- SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType);
- SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType);
- }
一旦设定了自定义语言驱动,你就可以在 mybatis-config.xml 文件中将它设置为默认语言:
- <typeAliases>
- <typeAlias type="org.sample.MyLanguageDriver" alias="myLanguage"/>
- </typeAliases>
- <settings>
- <setting name="defaultScriptingLanguage" value="myLanguage"/>
- </settings>
除了设置默认语言,你也可以针对特殊的语句指定特定语言,可以通过如下的 lang 属性来完成:
- <select id="selectBlog" lang="myLanguage">
- SELECT * FROM BLOG
- </select>
或者,如果你使用的是映射器接口类,在抽象方法上加上 @Lang 注解即可:
- public interface Mapper {
- @Lang(MyLanguageDriver.class)
- @Select("SELECT * FROM BLOG")
- List<Blog> selectBlog();
- }
注意 可以将 Apache Velocity 作为动态语言来使用,更多细节请参考 MyBatis-Velocity 项目。
你前面看到的所有 xml 标签都是由默认 MyBatis 语言提供的,而它由别名为 xml 的语言驱动器 org.apache.ibatis.scripting.xmltags.XmlLanguageDriver 所提供。
2.返回顶部 |
3.返回顶部 |
4.返回顶部 |
5.返回顶部 |
6.返回顶部 |
![]() |
作者:ylbtech 出处:http://ylbtech.cnblogs.com/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 |
Java-MyBatis:MyBatis 3 动态 SQL的更多相关文章
- 【mybatis深度历险系列】mybatis中的动态sql
最近一直做项目,博文很长时间没有更新了,今天抽空,学习了一下mybatis,并且总结一下.在前面的博文中,小编主要简单的介绍了mybatis中的输入和输出映射,并且通过demo简单的介绍了输入映射和输 ...
- Mybatis入门之动态sql
Mybatis入门之动态sql 通过mybatis提供的各种标签方法实现动态拼接sql. 1.if.where.sql.include标签(条件.sql片段) <sql id="sel ...
- mybatis 详解------动态SQL
mybatis 详解------动态SQL 目录 1.动态SQL:if 语句 2.动态SQL:if+where 语句 3.动态SQL:if+set 语句 4.动态SQL:choose(when,o ...
- mybatis中的动态SQL
在实际开发中,数据库的查询很难一蹴而就,我们往往要根据各种不同的场景拼接出不同的SQL语句,这无疑是一项复杂的工作,我们在使用mybatis时,mybatis给我们提供了动态SQL,可以让我们根据具体 ...
- Mybatis映射文件动态SQL语句-01
因为在很多业务逻辑复杂的项目中,往往不是简单的sql语句就能查询出来自己想要的数据,所有mybatis引入了动态sql语句, UserMapper.xml <?xml version=" ...
- Java下拼接运行动态SQL语句
mod=viewthread&tid=3039" target="_blank">Java拼接动态SQL的一般做法有 1.使用动态语句 非常多数 ...
- Java下拼接执行动态SQL语句(转)
在实际业务中经常需要拼接动态SQL来完成复杂数据计算,网上各类技术论坛都有讨论,比如下面这些问题: http://bbs.csdn.net/topics/390876591 http://bbs.cs ...
- 6.Mybatis中的动态Sql和Sql片段(Mybatis的一个核心)
动态Sql是Mybatis的核心,就是对我们的sql语句进行灵活的操作,他可以通过表达式,对sql语句进行判断,然后对其进行灵活的拼接和组装.可以简单的说成Mybatis中可以动态去的判断需不需要某些 ...
- mybatis框架(5)---动态sql
那么,问题来了: 什么是动态SQL? 动态SQL有什么作用? 传统的使用JDBC的方法,相信大家在组合复杂的的SQL语句的时候,需要去拼接,稍不注意哪怕少了个空格,都会导致错误.Mybatis的动态S ...
- mybatis教程4(动态SQL)
动态SQL语句 MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦.例如拼接时要确保不能忘记添加必要的空 ...
随机推荐
- Elasticsearch之curl创建索引库和索引时注意事项
前提, Elasticsearch之curl创建索引库 Elasticsearch之curl创建索引 注意事项 1.索引库名称必须要全部小写,不能以下划线开头,也不能包含逗号 2.如果没有明确指定索引 ...
- Android学习——控件ListView的使用
一.ListView的简单用法 首先新建一个ListViewTest项目,并让Android Studio自动创建好活动.然后修改activity_main.xml中的代码,如下: <?xml ...
- 统计学——Excel实现单(双)因素方差分析
笔记链接:http://www.cnblogs.com/igoslly/p/6784206.html 加载Excel“数据分析”工具包 [文件]→[选项]→[加载项]→[Excel加载项]→[转到] ...
- 当接口上配了 FeignClient 和 RequestMapping 两个注解,结果错误提示 重复mapping处理方法
再接手老文档的时候,发现有这么一个问题 错误显示为: 原文档写法: 解决方法: 这是一个编译时写法的问题,将上方的RequestMapping去掉,然后把路径放在下面的PostMapping 便可以正 ...
- jquey中的事件绑定
三种方法: $(selector).live(events, data, handler); // jQuery 1.3+ $(document).delegate(se ...
- (转载)tnsping不是内部或外部命令
手动添加 D:\app\Administrator\product\11.2.0\client_1\bin 到系统环境变量 path里面
- 将自己的类封装为lib的方法
前言: Windows API中所有的函数都包含在dll中,其中有3个最重要的DLL. (1) Kernel32.dll 它包含那些用于管理内存.进程和线程的函数,例如CreateThread函数 ...
- RabbitMQ学习笔记(4)----RabbitMQ Exchange(交换机)的使用
1. fanout模式 1.1 Publish/Subscribe(发布/订阅)结构图 上图表示一个消费者消费消息之后,不讲消息直接存储到队列,而是使用两个消费者各自声明一个队列,将各自的对应的队列与 ...
- 创建一个dynamics CRM workflow (四) - Development of Custom Workflows
首先我们需要确定windows workflow foundation 已经安装. 创建之后先移除MyCustomWorkflows 里面的 Activity.xaml 从packages\Micro ...
- 怎么用js或jq点击展开,出现隐藏的DIV,点击收起DIV又隐藏起来.
方法一:1 <script type="text/javascript"> $(function() { $("#toggle").click(fu ...