动态SQL

何为动态SQL??回顾一下我们之前写的SSH项目中,有多条件查询的情况,如下图

我们当时刚开始做的时候,是需要在Controller中判断SQL是否已经有条件了,因为SQL语句需要拼接起来….这样干的话,就非常容易出错的。

如下的代码,如果有多个条件的话,那么拼接起来很容易出错!


  1. public String listUI() {
  2. //查询语句
  3. String hql = "FROM Info i ";
  4. List<Object> objectList = new ArrayList<>();
  5. //根据info是否为null来判断是否是条件查询。如果info为空,那么是查询所有。
  6. if (info != null) {
  7. if (StringUtils.isNotBlank(info.getTitle())) {
  8. hql += "where i.title like ?";
  9. objectList.add("%" + info.getTitle() + "%");
  10. }
  11. }
  12. infoList = infoServiceImpl.findObjects(hql,objectList);
  13. ActionContext.getContext().getContextMap().put("infoTypeMap", Info.INFO_TYPE_MAP);
  14. return "listUI";
  15. }

后来,我们觉得这样不好,于是就专门写了一个查询助手类:


  1. package zhongfucheng.core.utils;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. /**
  5. * Created by ozc on 2017/6/7.
  6. */
  7. public class QueryHelper {
  8. private String fromClause = "";
  9. private String whereClause = "";
  10. private String orderbyClause = "";
  11. private List<Object> objectList;
  12. public static String ORDER_BY_ASC = "asc";
  13. public static String ORDER_BY_DESC = "desc";
  14. //FROM子句只出现一次
  15. /**
  16. * 构建FROM字句,并设置查询哪张表
  17. * @param aClass 用户想要操作的类型
  18. * @param alias 别名
  19. */
  20. public QueryHelper(Class aClass, String alias) {
  21. fromClause = " FROM " + aClass.getSimpleName() + " " + alias;
  22. }
  23. //WHERE字句可以添加多个条件,但WHERE关键字只出现一次
  24. /**
  25. * 构建WHERE字句
  26. * @param condition
  27. * @param objects
  28. * @return
  29. */
  30. public QueryHelper addCondition(String condition, Object... objects) {
  31. //如果已经有字符了,那么就说明已经有WHERE关键字了
  32. if (whereClause.length() > 0) {
  33. whereClause += " AND " + condition;
  34. } else {
  35. whereClause += " WHERE" + condition;
  36. }
  37. //在添加查询条件的时候,?对应的查询条件值
  38. if (objects == null) {
  39. objectList = new ArrayList<>();
  40. }
  41. for (Object object : objects) {
  42. objectList.add(object);
  43. }
  44. return this;
  45. }
  46. /**
  47. *
  48. * @param property 要排序的属性
  49. * @param order 是升序还是降序
  50. * @return
  51. */
  52. public QueryHelper orderBy(String property, String order) {
  53. //如果已经有字符了,那么就说明已经有ORDER关键字了
  54. if (orderbyClause.length() > 0) {
  55. orderbyClause += " , " + property +" " + order;
  56. } else {
  57. orderbyClause += " ORDER BY " + property+" " + order;
  58. }
  59. return this;
  60. }
  61. /**
  62. * 返回HQL语句
  63. */
  64. public String returnHQL() {
  65. return fromClause + whereClause + orderbyClause;
  66. }
  67. /**
  68. * 得到参数列表
  69. * @return
  70. */
  71. public List<Object> getObjectList() {
  72. return objectList;
  73. }
  74. }

这样一来的话,我们就不用自己手动拼接了,给我们的查询助手类去拼接就好了。

而如果我们使用Mybatis的话,就可以免去查询助手类了。因为Mybatis内部就有动态SQL的功能【动态SQL就是自动拼接SQL语句】

动态查询


  1. <!--多条件查询【动态SQL】-->
  2. <!--会自动组合成一个正常的WHERE字句-->
  3. <!--name值会从map中寻找-->
  4. <select id="findByCondition" resultMap="studentMap" parameterType="map">
  5. select * from students
  6. <where>
  7. <if test="name!=null">
  8. and name=#{name}
  9. </if>
  10. <if test="sal!=null">
  11. and sal &lt; #{sal}
  12. </if>
  13. </where>
  14. </select>

查询出来小于9000块的人


  1. public List<Student> findByCondition(String name,Double sal) throws Exception {
  2. //得到连接对象
  3. SqlSession sqlSession = MybatisUtil.getSqlSession();
  4. try{
  5. //映射文件的命名空间.SQL片段的ID,就可以调用对应的映射文件中的SQL
  6. /**
  7. * 由于我们的参数超过了两个,而方法中只有一个Object参数收集
  8. * 因此我们使用Map集合来装载我们的参数
  9. */
  10. Map<String, Object> map = new HashMap();
  11. map.put("name", name);
  12. map.put("sal", sal);
  13. return sqlSession.selectList("StudentID.findByCondition", map);
  14. }catch(Exception e){
  15. e.printStackTrace();
  16. sqlSession.rollback();
  17. throw e;
  18. }finally{
  19. MybatisUtil.closeSqlSession();
  20. }
  21. }
  22. public static void main(String[] args) throws Exception {
  23. StudentDao studentDao = new StudentDao();
  24. List<Student> students = studentDao.findByCondition(null,9000D);
  25. for (Student student : students) {
  26. System.out.println(student.getId() + "---" + student.getName() + "----" + student.getSal());
  27. }
  28. }

动态更新


  1. <!--动态更新-->
  2. <!--不要忘了逗号-->
  3. <update id="updateByConditions" parameterType="map">
  4. update students
  5. <set>
  6. <if test="name!=null">
  7. name = #{name},
  8. </if>
  9. <if test="sal!=null">
  10. sal = #{sal},
  11. </if>
  12. </set>
  13. where id = #{id}
  14. </update>

给出三个更新的字段


  1. public void updateByConditions(int id,String name,Double sal) throws Exception {
  2. //得到连接对象
  3. SqlSession sqlSession = MybatisUtil.getSqlSession();
  4. try{
  5. //映射文件的命名空间.SQL片段的ID,就可以调用对应的映射文件中的SQL
  6. /**
  7. * 由于我们的参数超过了两个,而方法中只有一个Object参数收集
  8. * 因此我们使用Map集合来装载我们的参数
  9. */
  10. Map<String, Object> map = new HashMap();
  11. map.put("id", id);
  12. map.put("name", name);
  13. map.put("sal", sal);
  14. sqlSession.update("StudentID.updateByConditions", map);
  15. sqlSession.commit();
  16. }catch(Exception e){
  17. e.printStackTrace();
  18. sqlSession.rollback();
  19. throw e;
  20. }finally{
  21. MybatisUtil.closeSqlSession();
  22. }
  23. }
  24. public static void main(String[] args) throws Exception {
  25. StudentDao studentDao = new StudentDao();
  26. studentDao.updateByConditions(2,"haha",500D);
  27. }

动态删除



以前我们使用JDBC也好,Hibernate也好,想要批量删除的时候,总是使用的是循环删除。而我们现在使用的是Mybatis,SQL语句是自己写的。所以我们可以写下如下的SQL来进行删除


  1. delete from students where id in (?,?,?,?);

而我们的Mybatis又支持动态SQL,所以删除起来就非常方便了!


  1. <delete id="deleteByConditions" parameterType="int">
  2. <!-- foreach用于迭代数组元素
  3. open表示开始符号
  4. close表示结束符合
  5. separator表示元素间的分隔符
  6. item表示迭代的数组,属性值可以任意,但提倡与方法的数组名相同
  7. #{ids}表示数组中的每个元素值
  8. -->
  9. delete from students where id in
  10. <foreach collection="array" open="(" close=")" separator="," item="ids">
  11. #{ids}
  12. </foreach>
  13. </delete>

删除编号为2,3,4的记录

  1. public void deleteByConditions(int... ids) throws Exception {
  2. //得到连接对象
  3. SqlSession sqlSession = MybatisUtil.getSqlSession();
  4. try{
  5. //映射文件的命名空间.SQL片段的ID,就可以调用对应的映射文件中的SQL
  6. /**
  7. * 由于我们的参数超过了两个,而方法中只有一个Object参数收集
  8. * 因此我们使用Map集合来装载我们的参数
  9. */
  10. sqlSession.delete("StudentID.deleteByConditions", ids);
  11. sqlSession.commit();
  12. }catch(Exception e){
  13. e.printStackTrace();
  14. sqlSession.rollback();
  15. throw e;
  16. }finally{
  17. MybatisUtil.closeSqlSession();
  18. }
  19. }
  20. public static void main(String[] args) throws Exception {
  21. StudentDao studentDao = new StudentDao();
  22. studentDao.deleteByConditions(2,3,4);
  23. }

动态插入

我们要想动态插入的话,就比其他的DML语句稍微复杂一点,因为它有两部分是不确定的,平常的SQL语句是这样的:


  1. insert into student(id,name,sal) values(?,?,?)

SQL代码块是不能像之前那样帮我们自动去除多余的逗号的,因此我们需要使用trim标签来自己手动去除…

编写insertSQL语句的时候,不要忘了写()括号。


  1. <!--SQL片段默认是不帮我们自动生成合适的SQL,因此需要我们自己手动除去逗号-->
  2. <sql id="key">
  3. <trim suffixOverrides=",">
  4. <if test="id!=null">
  5. id,
  6. </if>
  7. <if test="id!=null">
  8. name,
  9. </if>
  10. <if test="id!=null">
  11. sal,
  12. </if>
  13. </trim>
  14. </sql>
  15. <sql id="value">
  16. <trim suffixOverrides=",">
  17. <if test="id!=null">
  18. #{id},
  19. </if>
  20. <if test="id!=null">
  21. #{name},
  22. </if>
  23. <if test="id!=null">
  24. #{sal},
  25. </if>
  26. </trim>
  27. </sql>
  28. <!--动态插入-->
  29. <insert id="insertByConditions" parameterType="zhongfucheng.Student">
  30. insert into students (<include refid="key"/>) values
  31. (<include refid="value"/>)
  32. </insert>

测试三个不同内容的数据


  1. public void insertByConditions(Student student) throws Exception {
  2. //得到连接对象
  3. SqlSession sqlSession = MybatisUtil.getSqlSession();
  4. try{
  5. //映射文件的命名空间.SQL片段的ID,就可以调用对应的映射文件中的SQL
  6. sqlSession.insert("StudentID.insertByConditions", student);
  7. sqlSession.commit();
  8. }catch(Exception e){
  9. e.printStackTrace();
  10. sqlSession.rollback();
  11. throw e;
  12. }finally{
  13. MybatisUtil.closeSqlSession();
  14. }
  15. }
  16. public static void main(String[] args) throws Exception {
  17. StudentDao studentDao = new StudentDao();
  18. studentDao.insertByConditions(new Student(55, null, null));//name和sal为空
  19. studentDao.insertByConditions(new Student(66, "haxi", null));//sal为空
  20. studentDao.insertByConditions(new Student(77, null, 3999d));//name为空
  21. }

Mybatis第三篇【动态SQL】的更多相关文章

  1. MyBatis(三)动态SQL与缓存

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.动态SQL语句 准备工作: public class User { private int id; ...

  2. Mybatis(三)动态sql语句

    动态sql语句操作 1.MyBatis中#{ }和${ }的区别 在 mapper 中定义的参数传到 xml 中之后,在查询之前 mybatis 会对其进行动态解析.mybatis 为我们提供了两种支 ...

  3. MyBatis学习 之 三、动态SQL语句

    目录(?)[-] 三动态SQL语句 selectKey 标签 if标签 if where 的条件判断 if set 的更新语句 if trim代替whereset标签 trim代替set choose ...

  4. Mybatis学习系列(三)动态SQL

    在mapper配置文件中,有时需要根据查询条件选择不同的SQL语句,或者将一些使用频率高的SQL语句单独配置,在需要使用的地方引用.Mybatis的一个特性:动态SQL,来解决这个问题. mybati ...

  5. MyBatis学习总结_11_MyBatis动态Sql语句

    MyBatis中对数据库的操作,有时要带一些条件,因此动态SQL语句非常有必要,下面就主要来讲讲几个常用的动态SQL语句的语法 MyBatis中用于实现动态SQL的元素主要有: if choose(w ...

  6. MyBatis 注解配置及动态SQL

      一.注解配置 目前MyBatis支持注解配置,用注解方式来替代映射文件,但是注解配置还是有点不完善,在开发中使用比较少,大部分的企业还是在用映射文件来进行配置.不完善的地方体现在于当数据表中的字段 ...

  7. MyBatis:学习笔记(4)——动态SQL

    MyBatis:学习笔记(4)——动态SQL

  8. SSM框架之Mybatis(6)动态SQL

    Mybatis(6)动态SQL 1.动态SQL 出现原因:有些时候业务逻辑复杂时,我们的 SQL 是动态变化的,此时在前面的学习中我们的 SQL 就不能满足要求了 1.1.if标签 我们根据实体类的不 ...

  9. Spring mybatis源码篇章-动态SQL节点源码深入

    通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-动态SQL基础语法以及原理 前话 前文描述到通过mybatis默认的解析驱动类org.apache.ibat ...

随机推荐

  1. MySQL中count(1),count(*),count(col)的区别

    count(*)返回行数的时候不管列中的值是不是null,在MyISAM表中,count(*)被优化,因为在MyISAM表中,行数被额外存储了,所以会很快,但是这个时候不能有where条件.innod ...

  2. js中高度与宽度的获取

    JS获取各种宽度.高度的简单介绍: scrollHeight: 获取对象的滚动高度. scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离 scrollTop:设置或获 ...

  3. 自制简易Linux系统

    l 要求: 裁剪一个装载有网卡驱动可以上网并且使用到init的一个小系统 l 准备: 虚拟机,centos6.4 l 步骤: 一.在宿主机上添加一块硬盘,并为其安装grub 1. 在宿主机上添加一块硬 ...

  4. 一起学ASP.NET Core 2.0学习笔记(一): CentOS下 .net core2 sdk nginx、supervisor、mysql环境搭建

    作为.neter,看到.net core 2.0的正式发布,心里是有点小激动的,迫不及待的体验了一把,发现速度确实是快了很多,其中也遇到一些小问题,所以整理了一些学习笔记: 阅读目录 环境说明 安装C ...

  5. 获取token之后,再调用匿名方法

    js获取token bpm.api.beginDownload = function (filePath, fileName) { var url = "/Home/GetToken&quo ...

  6. Python3使用Print输出带颜色字体

    Phton3使用print输出带颜色的彩色字体 实现过程:       终端的字符颜色是用转义序列控制的,是文本模式下的系统显示功能,和具体的语言无关.       转义序列是以ESC开头,即用\03 ...

  7. spring boot / cloud (十五) 分布式调度中心进阶

    spring boot / cloud (十五) 分布式调度中心进阶 在<spring boot / cloud (十) 使用quartz搭建调度中心>这篇文章中介绍了如何在spring ...

  8. hbase1.1.4集群搭建

    hbase1.1.4集群搭建 先部署一个zookeeper集群和hadoop集群. (1)上传hbase安装包到intsmaze01节点 (2)解压 (3)配置hbase集群,要修改3个文件 注意:要 ...

  9. open文件操作之mode模式剖析

    Python可以使用open函数来实现文件的打开,关闭,读写操作: Python3中的open函数定义为: open(file, mode='r', buffering=None, encoding= ...

  10. Java入门——学会使用API

    API是什么? API(Application Programming Interface)就是别人写的代码使用说明书. 下面是中文版API的使用具体截图. 1.左上角有个显示(图中"隐藏& ...