博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MyBatis学习笔记4——动态 SQL
阅读量:3942 次
发布时间:2019-05-24

本文共 4179 字,大约阅读时间需要 13 分钟。

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 子句的一部分。比如:

这条语句提供了一种可选的查找文本功能。如果没有传入“title”,那么所有处于“ACTIVE”状态的BLOG都会返回;反之若传入了“title”,那么就会对“title”一列进行模糊查找并返回 BLOG 结果(“title”参数值是可以包含一些掩码或通配符的)。

如果希望通过“title”和“author”两个参数进行可选搜索该怎么办呢?首先,改变语句的名称让它更具实际意义;然后只要加入另一个条件即可。

choose, when, otherwise

有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

还是上面的例子,但是这次变为提供了“title”就按“title”查找,提供了“author”就按“author”查找的情形,若两者都没有提供,就返回所有符合条件的 BLOG(实际情况可能是由管理员按一定策略选出 BLOG 列表,而不是返回大量无意义的随机结果)。

trim, where, set

现在回到“if”示例,这次我们将“ACTIVE = 1”也设置成动态的条件,看看会发生什么。

如果这些条件没有一个能匹配上会发生什么?最终这条 SQL 会变成这样:

SELECT * FROM BLOGWHERE

这会导致查询失败。如果仅仅第二个条件匹配又会怎样?这条 SQL 最终会是这样:

SELECT * FROM BLOGWHERE AND title like ‘someTitle’

这个查询也会失败。这个问题不能简单地用条件句式来解决。

MyBatis 有一个简单的处理,这在 90% 的情况下都会有用。而在不能使用的地方,你可以自定义处理方式来令其正常工作。一处简单的修改就能达到目的:

where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“ORwhere 元素也会将它们去除

如果 where 元素没有按正常套路出牌,我们可以通过自定义 trim 元素来定制 where 元素的功能。比如,where 元素等价的自定义 trim 元素为:

...

prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它的作用是移除SQL语句中第一个在 prefixOverrides 属性中指定的内容(即ANDOR,并且插入 prefix 属性中指定的内容(即WHERE

类似的用于动态更新语句的解决方案叫做 setset 元素可以用于动态包含需要更新的列,而舍去其它的。比如:

update Author
username=#{username},
password=#{password},
email=#{email},
bio=#{bio}
where id=#{id}

这里,set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号,因为用了条件语句之后很可能就会在生成的 SQL 语句的后面留下这些逗号。(因为用的是“if”元素,若最后一个“if”没有匹配上而前面的匹配上,SQL 语句的最后就会有一个逗号遗留)。

若你对 set 元素等价的自定义 trim 元素的代码感兴趣,那这就是它的真面目:

...

注意这里我们删去的是后缀值,同时添加了前缀值

foreach

动态 SQL 的另外一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候。比如:

foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及在迭代结果之间放置分隔符。这个元素是很智能的,因此它不会偶然地附加多余的分隔符

可以将任何可迭代对象(如 ListSet 等)、Map 对象或者数组对象传递给 foreach 作为集合参数。当使用可迭代对象或者数组时,index 是当前迭代的次数,item 的值是本次迭代获取的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

bind

bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如:

多数据库支持

一个配置了“_databaseId”变量的 databaseIdProvider 可用于动态代码中,这样就可以根据不同的数据库厂商构建特定的语句。比如下面的例子:

select seq_users.nextval from dual
select nextval for seq_users from sysibm.sysdummy1"
insert into users values (#{id}, #{name})

动态 SQL 中的可插拔脚本语言

MyBatis3.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 文件中将它设置为默认语言:

除了设置默认语言,你也可以针对特殊的语句指定特定语言,可以通过如下的 lang 属性来完成:

或者,如果你使用的是映射器接口类,在抽象方法上加上 @Lang 注解即可:

public interface Mapper {
@Lang(MyLanguageDriver.class) @Select("SELECT * FROM BLOG") List
selectBlog();}

转载地址:http://eriwi.baihongyu.com/

你可能感兴趣的文章
yaf使用小记
查看>>
document.domain 跨域问题
查看>>
window安装PHP的redis扩展
查看>>
给网站选择一个好的jquery库远程调…
查看>>
flash as 与js通信(转)
查看>>
Linux系统手动安装rzsz 软件包
查看>>
PHP的事务处理机制
查看>>
JS moveStart和moveEnd方法
查看>>
thrift的lua实现
查看>>
编写高性能的Lua代码
查看>>
Python正则表达式指南
查看>>
LUA--thrift--lib库的创建生成
查看>>
Shell开启扩展模式匹配shopt -s extglob
查看>>
浅谈 URI 及其转义
查看>>
nginx 优化
查看>>
openresty+lua在反向代理服务中的玩法
查看>>
ClickHouse集群搭建从0到1
查看>>
nginx实现请求的负载均衡 + keepalived实现nginx的高可用
查看>>
linux shell 中数组的定义和for循环遍历的方法
查看>>
求1!+2!+3!....+20!(java代码)
查看>>