MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑。

例如,sql语句where条件中,需要一些安全判断,例如按某一条件查询时如果传入的参数是空,此时查询出的结果很可能是空的,也许我们需要参数为空时,是查出全部的信息

MyBatis中用于实现动态SQL的元素主要有:

  • if
  • choose(when,otherwise)
  • trim
  • where
  • set
  • foreach
示例mapper.xml:
 
  1. <select id="findActiveBlogLike"
  2. parameterType="BLOG" resultType="BLOG">
  3. SELECT * FROM BLOG
  4. WHERE
  5. <trim prefix="WHERE" prefixOverrides="AND |OR ">
  6. <choose>
  7. <when test="title != null">
  8. AND title like #{title}
  9. </when>
  10. <when test="author != null and author.name != null">
  11. AND title like #{author.name}
  12. </when>
  13. <otherwise>
  14. AND featured = 1
  15. </otherwise>
  16. </choose>
  17. </trim>
  18. </select>
  19. <update id="updateAuthorIfNecessary"
  20. parameterType="Author">
  21. update Author
  22. <trim prefix="where" prefixOverrides=",">
  23. <set>
  24. <if test="username != null">username=#{username},</if>
  25. <if test="password != null">password=#{password},</if>
  26. <if test="email != null">email=#{email}</if>
  27. </set>
  28. where id=#{id}
  29. </trim>
  30. </update>
但是问题来了,如果我们没有实体怎么办?如上代码,都是关联实体Author,BLOG。
更进一步,如果我们连字段和表名都是程序运行时产生的,那么在Mybatis中,我们的mapper.xml又该如何写呢?
 
不要说这种需求很少,实际上很多灵活性和扩展性要求比较高的应用,物理模型不确定,也即是你的表结构不确定,甚至连表名字都不确定,基本上sql中的每一个字母都不是写死的。
 
我现在就遇到了这种需求,简单描述如下:
事先定义好了很多数据集的信息模型,针对这些信息模型生成物理模型。而我们需要针对这些物理模型进行操作。而这些数据集一旦更新,信息模型以及物理模型都要变动,所以事先不可能完全确定物理表结构等等信息。此时应该怎么在mybatis中进行处理呢?
 

翻阅mybatis文档,在一个不起眼的地方发现update标签有一个属性statementType,根据jdbc的经验,这应该是控制sql预编译还是非预编译的,如果sql执行是预编译的,那么动态传入字段名,表名之类的,显然

是不行的,所以你必须改成非预编译的。

两者有什么区别呢?如果是预编译的,那么系统在初始化时就会读取这段sql代码,将指定的实体类中的字段替换了类似#{}这样的语句,就是形成了类似这样的语句:

"select * from tableName where id=?" 这个时候你在系统运行时再想向这句sql中替换tableName或者id,结果可想而知。如果是非预编译呢,结果刚好相反,他会在系统运行时才会去生成这样类似的语句。此时就可以去替换这些动态的字段或者表名之类。这样在结合之前所讲的返回类型的设置,我们的问题就解决了。

我们可以不用设定参数和返回类型的实体类,只需要形成一个动态的表名和字段名的列表类。就可以动态对那些未知的物理模型进行操作.如下代码可作参考:

  1. <select id="queryMetaList" resultType="Map" statementType="STATEMENT">
  2. select * from ${tableName} t where
  3. <foreach item="item" index="index" collection="field" open=" "
  4. separator="and" close=" ">
  5. <choose>
  6. <when test="item.fieldType == 'DATE' and item.dateQueryFlag == 0">
  7. ${item.fieldCode} between
  8. to_date('${item.fieldValue}','yyyy-mm-dd
  9. hh24:mi:ss')
  10. </when>
  11. <when test="item.fieldType == 'DATE' and item.dateQueryFlag == 1">
  12. to_date('${item.fieldValue}','yyyy-mm-dd
  13. hh24:mi:ss')
  14. </when>
  15. <when test="item.fieldItemCode != null and item.fieldItemCode != ''">
  16. ${item.fieldCode} =
  17. '${item.fieldItemCode}'
  18. </when>
  19. <otherwise>
  20. ${item.fieldCode} =
  21. '${item.fieldValue}'
  22. </otherwise>
  23. </choose>
  24. </foreach>
  25. </select>
注:会有sql注入危险,代码中要处理。
 
另外,注意返回值,在mybatis中,无论你指定还是不指定返回类型,mybatis都会默认的先将查询回的值放入一个hashMap中(如果返回的值不止一条就是一个包含hashMap的list)。这其中的区别在于,如果你指定了返回类型,mybatis将会根据返回类型的实体类来从hashMap中获取值并set到这个实体类中。如果不指定就默认返回一个HashMap<String,Object>(List<HashMap<String,Object>>)。
 
我们没有实体,当然就不要指定返回值,默认接受处理List<HashMap<String,Object>>结构的返回值即可。

Mybatis动态构建Sql(无实体类)的更多相关文章

  1. 模拟实现MyBatis中通过SQL反射实体类对象功能

    话不多说,直接上干货! package cn.test; import java.lang.reflect.Method; import java.sql.Connection; import jav ...

  2. Mybatis之动态构建SQL语句

    今天一个新同事问我,我知道如何利用XML的方式来构建动态SQL,可是Mybatis是否能够利用注解完成动态SQL的构建呢?!!答案是肯定的,MyBatis 提供了注解,@InsertProvider, ...

  3. 通过模拟Mybatis动态代理生成Mapper代理类,讲解Mybatis核心原理

    本文将通过模拟Mybatis动态代理生成Mapper代理类,讲解Mybatis原理 1.平常我们是如何使用Mapper的 先写一个简单的UserMapper,它包含一个全表查询的方法,代码如下 pub ...

  4. mybatis的基本配置:实体类、配置文件、映射文件、工具类 、mapper接口

    搭建项目 一:lib(关于框架的jar包和数据库驱动的jar包) 1,第一步:先把mybatis的核心类库放进lib里

  5. 使用MyBatis的Generator自动创建实体类和dao的接口与xml

    在实际的项目中其实建立数据库和设计数据库的时候特别重要,而等数据库设计完成之后,根据数据库创建实体类的工作就特别麻烦和繁琐了,不仅很麻烦,而且很浪费时间,不做又不行,这次就找到了一个简单的方法可以让m ...

  6. MyBatis——解决字段名与实体类属性名不相同的冲突

    原文:http://www.cnblogs.com/xdp-gacl/p/4264425.html 在平时的开发中,我们表中的字段名和表对应实体类的属性名称不一定都是完全相同的,下面来演示一下这种情况 ...

  7. MyBatis解决字段名与实体类属性名不相同的冲突(四)

    一.创建表和表数据 CREATE TABLE orders( order_id INT PRIMARY KEY AUTO_INCREMENT, order_no ), order_price FLOA ...

  8. Mybatis解决字段名与实体类属性名不相同的冲突

    在平时的开发中,我们表中的字段名和表对应实体类的属性名称不一定都是完全相同的,下面来演示一下这种情况下的如何解决字段名与实体类属性名不相同的冲突. 一.准备演示需要使用的表和数据 CREATE TAB ...

  9. mybatis中映射文件和实体类的关联性

    mybatis的映射文件写法多种多样,不同的写法和用法,在实际开发过程中所消耗的开发时间.维护时间有很大差别,今天我就把我认为比较简单的一种映射文件写法记录下来,供大家修改建议,争取找到一个最优写法~ ...

随机推荐

  1. Linux系统在启动过程中grub引导文件丢失的解决方法

    在/boot/grub2目录下有一个grub.cfg文件:该文件主要是用来自动地引导系统启动内核程序和系统的初始化程序. 问题一:当系统在启动的情况下,我们不小心删除/boot/grub2/grub. ...

  2. c++下使用命名管道实现进程间通信

    前面已经使用邮槽实现过进程间通信:http://www.cnblogs.com/jzincnblogs/p/5192654.html ,这里使用命名管道实现进程间通信. 与邮槽不同的是,命名管道在进程 ...

  3. jQuery扩展 模糊删除sessionStroage

    $.extend({ removeStorageLike : function(name){ //模糊删除 for(var k in sessionStorage){ if(k.indexOf(nam ...

  4. 主机屋MySQL数据库链接

    点击高级设置,进入Myadmin,导入数据 要注意,数据库名字不能变,这是人家给的. 在php链接时,: $db=[ // 服务器地址 'hostname' => 'localhost', // ...

  5. UICollectionView 数据库元素分组 多种section分开显示

    第一遍 复杂方法 : 数据库查询一个表中userID 然后进行分类 中间去重 获得ID个数  放到section 中  显示 #pragma mark -  查询不同的ID 各数  - (void)c ...

  6. PPP of DDD

    我是真够懒的了

  7. Java启动参数及调优

    java启动参数共分为三类: 其一是标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容:其二是非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且 ...

  8. 《DSP using MATLAB》示例Example 8.23

    代码: %% ------------------------------------------------------------------------ %% Output Info about ...

  9. 浅谈ES6新特性

    ES6的了解 新增模板字符串(为JavaScript提供了简单的字符串插值功能).箭头函数(操作符左边为输入的参数,而右边则是进行的操作以及返回的值Inputs=>outputs.).for-o ...

  10. fabio 安装试用&&实际使用的几个问题

    备注:    因为fabio 依赖consul vault (不是强需),启动之前需要先安装consul,    本次为了简单consul 使用的是单机,使用的是dev 模式   1. conusl ...