背景

××项目需要提供系统部分函数第三方调用接口,基于安全性和避免暴露数据库表信息的基础上进行函数接口的设计,根据第三方调用身份的权限提供某张表的自定义集合。本项目基于mybatis的持久层框架,支持定制化的SQL,这样可以避免拼接sql语句的痛苦。例如拼接时要确保不能添加空格,还要注意去掉列表的最后一个列名的都逗号。基于OGNL的表达式的mybatis框架可以彻底解决这种痛苦。

动态返回mysql某张表指定列的名字,类型和注释

<select id="queryColumns" resultType="map" parameterType="java.util.HashMap">
select column_name columnName, data_type dataType, column_comment columnComment
from information_schema.columns
where table_name = #{tablename}
and
column_name in
<foreach collection="columnsArray" item="column_name" index="index" open="(" close=")" separator=",">
#{column_name}
</foreach>
</select>

动态查询某个表的指定列数据

<select id="query1" resultType="map"  parameterType="java.util.HashMap">
select
<foreach collection="columnsArray" item="item" index="index" open=" " separator=", " close=" " >
${item}
</foreach>
from #{tableName} tn
</select>

利用 if和foreach元素动态的拼接where 条件部分

<select id="query2" resultType="map" parameterType="java.util.HashMap">
select
<foreach collection="columnsArray" item="item" index="index" open="" separator="," close="" >
${item}
</foreach>
from #{tableName} db
where
<if test ="name !=null">
db.name=#{name} and
</if>
db.LastModifyTime between #{datestart,jdbcType=TIMESTAMP} and #{dateend,jdbcType=TIMESTAMP}
</select>

传参数 ${} 和#{}区别

Mybatis 的Mapper.xml语句中parameterType向SQL语句传参有两种方式:#{}和${}

我们经常使用的是#{},一般解说是因为这种方式可以防止SQL注入,简单的说#{}这种方式SQL语句是经过预编译的,它是把#{}中间的参数转义成字符串,举个例子:

select * from student where studentName = #{name} 

预编译后,会动态解析成一个参数标记符?:

select * from student where studentName = ?

而使用${}在动态解析时候,会传入参数字符串

select * from student where studentName = 'lyrics'

-看完上面的一些例子,可以看到主要用到了if 、foreach等元素,mybatis之前的版本,有很多的元素需要了解,而mybatis大大精简了元素种类,现在只需要学习以下几个元素:

-if

-choose(when,otherwise)

-trim(where,set)

-foreach

-- 引用[http://www.mybatis.org/mybatis-3/zh/dynamic-sql.html]

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)变量。它也允许你指定开头与结尾的字符串以及在迭代结果之间放置分隔符。这个元素是很智能的,因此它不会偶然地附加多余的分隔符。

-释义:

-collection :collection属性的值有三个分别是list、array、map三种,分别对应的参数类型为:List、array、map,上面传的参数为数组,所以值为array

-item : 表示在迭代过程中每一个元素的别名

 -index :表示在迭代过程中每次迭代到的位置(下标)

 -open :前缀

 -close :后缀

 -separator :分隔符,表示迭代时每个元素之间以什么分隔

我们通常可以将之用到批量删除、添加等操作中。

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

mybatis 动态SQL查询总结的更多相关文章

  1. MyBatis 动态SQL查询,多条件,分页

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-/ ...

  2. mybatis实战教程(mybatis in action)之八:mybatis 动态sql语句

    mybatis 的动态sql语句是基于OGNL表达式的.可以方便的在 sql 语句中实现某些逻辑. 总体说来mybatis 动态SQL 语句主要有以下几类:1. if 语句 (简单的条件判断)2. c ...

  3. mybatis动态SQL标签的用法

    动态 SQL MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦.拼接的时候要确保不能忘了必要的空格 ...

  4. 9.mybatis动态SQL标签的用法

    mybatis动态SQL标签的用法   动态 SQL MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么 ...

  5. 超全MyBatis动态SQL详解!( 看完SQL爽多了)

    MyBatis 令人喜欢的一大特性就是动态 SQL. 在使用 JDBC 的过程中, 根据条件进行 SQL 的拼接是很麻烦且很容易出错的. MyBatis 动态 SQL 的出现, 解决了这个麻烦. My ...

  6. Mybatis动态SQL简单了解 Mybatis简介(四)

    动态SQL概况 MyBatis 的强大特性之一便是它的动态 SQL 在Java开发中经常遇到条件判断,比如: if(x>0){ //执行一些逻辑........ }   Mybatis应用中,S ...

  7. mybatis原理分析学习记录,mybatis动态sql学习记录

    以下个人学习笔记,仅供参考,欢迎指正. MyBatis 是支持定制化 SQL.存储过程以及高级映射的持久层框架,其主要就完成2件事情: 封装JDBC操作 利用反射打通Java类与SQL语句之间的相互转 ...

  8. mybatis 动态sql和参数

    mybatis 动态sql 名词解析 OGNL表达式 OGNL,全称为Object-Graph Navigation Language,它是一个功能强大的表达式语言,用来获取和设置Java对象的属性, ...

  9. mybatis 动态 SQL 官方文档

    MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦.例如拼接时要确保不能忘记添加必要的空格,还要注意去掉 ...

随机推荐

  1. better-scroll 滑动插件的使用

    better-scroll 滑动插件的使用 拥有的效果:下拉刷新.上拉加载.滑动.轮播

  2. ImportError: cannot import name 'Document'

    一种常见的原因是,程序文件的名字不对. 程序文件的名字不能和 import lib 里的名字冲突. 一个例子: 如果程序文件名字是 docx.py,程序又 from docx import Docum ...

  3. FragmentFactory

    import android.support.v4.app.Fragment; import java.util.HashMap; public class FragmentFactory { pri ...

  4. Django测试环境环境配置

    安装Django 在cmd的管理者模式下进入Python的安装目录 敲入命令:pip install Django -看到如下的信息表示成功 如果你在运行其它人写的Django系统时出现以下错误信息, ...

  5. nginx不记录指定文件类型的日志

    1.指定记录文件日志记录的内容. vim /usr/local/nginx/conf/nginx.conf如下部分: log_format dd '$remote_addr $http_x_forwa ...

  6. 阶段3 3.SpringMVC·_01.SpringMVC概述及入门案例_06.入门案例的流程总结

    配置了load-on-startup等于1 表示启动了服务器就会去创建DispatcherServlet 如果不配置load-on-startup为1 那么第一次发送请求才会去创建Dispatcher ...

  7. vim技巧1

    在编辑模式或可视模式下输入的命令会另外注明.1. 查找   /xxx(?xxx)       表示在整篇文档中搜索匹配xxx的字符串, / 表示向下查找, ? 表示                   ...

  8. RedHat 5下安装gcc编译环境的具体步骤

    RedHat 5下安装gcc编译环境的具体步骤 在RHEL5系统中默认不安装linux系统中的开发编译环境(gcc),此软件包安装时依赖其他包较多 在以前使用RHEL4时可以通过如下命令安装: rpm ...

  9. mac打开已损坏或者不明来源的应用的解决方法

    如遇:「xxx.app已损坏,打不开.你应该将它移到废纸篓」,并非你安装的软件已损坏,而是Mac系统的安全设置问题,因为这些应用都是破解或者汉化的,那么解决方法就是临时改变Mac系统安全设置.出现这个 ...

  10. mybatis generator 源码修改

    项目中使用mybatis + 通用mapper,用mybatis generator生成代码时有些不方便,参考了网上的一些例子,修改mybatis genrerator的源码. 首先,下载mybati ...