动态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. 常用perl脚本工具

    1.批量添加license:PrefixLicense.pl (1)给单一c/c++源文件添加license: perl PrefixLicense.pl apache_license src_fil ...

  2. markdownpad生成目录

    生成目录 document.addEventListener("DOMContentLoaded", function() { // 生成目录列表 var outline = do ...

  3. 优化testng报告

    背景 搞过testng的同学都知道,testng自带的报告非常丑,而且有些字段的展示很不人性化,所以需要优化下报告 解决方案 尝试过一下开源的jar包,如ReportNG,奈何和目前使用的allure ...

  4. LAMP环境的搭建(三)----PHP7的安装

    centos自带的PHP源是5.4版本的.如果需要安装PHP 5.4 直接输入 yum install php -y 即可 因为PHP7性能巨大的提升,因此本文选择安装PHP7 如果已经安装过了php ...

  5. Python初学——窗口视窗Tkinter

    此篇文章是跟着沫凡小哥的视频学习的,附上学习网址:https://morvanzhou.github.io/tutorials/python-basic/ 什么是 tkinter 窗口1.1 什么是 ...

  6. [2013-02-22]info入门FAQ

    linux相关的东西,入门最快捷,最通用的方式无非查阅帮助文档. man命令很好理解,就不讲了,这里就提几个info相关的FAQ(也就3点啦) 基本操作,如何入门info 首先,输入info命令 ,进 ...

  7. 常用的十大Python开发工具

    据权威机构统计,Python人才需求量每日高达5000+,但目前市场上会 Python 的程序员少之又少, 竞争小,很容易快速高薪就业.可能你并不太了解常用的十大Python开发工具都有哪些,现在告诉 ...

  8. wifi pineapple 外接USB无线网卡桥接外网

    0:选择USB网卡 在没有有线网络的情况下,可以外挂一个usb无线网卡来桥接上网,目前支持3070L.8187L芯片的网卡,反正linux系统都用这些芯片, 免的安装驱动, 我选择的是 WN-722N ...

  9. C++ Concept 和Java 接口

    C++ Concept 和Java 接口 Concept及接口 我会用Java写个case来解释什么是C++的Concept.Concept可以理解为接口,它是一种广义的接口.不同于Java的Inte ...

  10. JavaScript在应用中的技巧(二)

    ==,===运算符和强制转换 先看个表达式: "1.0e0" == { valueOf: function() { return true; } }; 是的,这个结果可能有点出乎意 ...