If标签

动态SQL可以说是MyBatis最强大之处了,这块的应用主要有四个方面if,choose,trim和foreach,接下来先说说if。

顾名思义,if是用来判断条件的,现在假设我们有个需求,原先我们查询员工是靠id查询的,现在提出新的要求,要求用户输入携带了哪个字段查询条件就带上这个字段的值,

  1. List<Employee> getEmpsByConditionIf(Employee e);  

那么这个sql语句该怎么写呢?

  1. <select id="EmployeeMapperDynamicTest" resultType="com.figsprite.bean.Employee">  
  2.     select * from tb_employee where id = #{id} and last_name like #{lastName}  
  3.     and email = #{email} and gender=#{gender}  
  4. </select> 

这种写法显然是有问题的,如果传入的Employee中lastName为空,这个select语句就查不出我们想要的结果,还有很多类似的情况,此时,就要使用到if,<if test=""></if>,test属性中采用的是OGNL表达式,与EL表达式和你像,大家可以去官网查找具体的内容[http://commons.apache.org/proper/commons-ognl/download_ognl.cgi]

在书写test属性中的OGNL时要注意遇到特殊符号应该写转移字符,比如&要写成&amp;;

具体的对应关系可以查找W3C的手册:

[https://www.w3cschool.cn/htmltags/ref-entities.html]

  1. <select id="getEmpsByConditionIf" resultType="com.figsprite.bean.Employee">  
  2.     select * from tb_employee  
  3.     <if test="id!=null">  
  4.         id = #{id}  
  5.     </if>  
  6.     <if test="lastName!=null and lastName!=""">  
  7.         and last_name like #{lastName}  
  8.     </if>  
  9.     <if test="email!=null and email.trim()!=""">  
  10.         and email = #{email}  
  11.     </if>  
  12.     <if test="gender==0 or gender==1">  
  13.         gender=#{gender}  
  14.     </if>  
  15. </select>

注意两点1.email判断时用到了email.trim() 2.gender原本是字符串,可此处将它当做是是数字,OGNL会进行字符串与数字的转化判断.

做一下测试:

  1. public static SqlSessionFactory getSqlSessionFactory() throws IOException {  
  2.     String resource = "mybatis-conf.xml";  
  3.     InputStream inputStream = Resources.getResourceAsStream(resource);  
  4.     
  5.     return new SqlSessionFactoryBuilder().build(inputStream);  
  6. }  
  7.     
  8. @Test  
  9. public void testGetEmpsByConditionIf() throws IOException {  
  10.     SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();  
  11.     SqlSession openSession = sqlSessionFactory.openSession();  
  12.     try {  
  13.         EmployeeMapperDynamic mapper = openSession.getMapper(EmployeeMapperDynamic.class);  
  14.         Employee e = new Employee();  
  15.         e.setId(5);  
  16.         e.setLastName("%青%");  
  17.         List<Employee> employeeList = mapper.getEmpsByConditionIf(e);  
  18.         for (Employee employee:employeeList){  
  19.             System.out.println(employee);  
  20.         }  
  21.     }finally {  
  22.         openSession.close();  
  23.     }  
  24. }  

结果:Employee{id=5, lastName='吴青宁', gender='1', email='wq', department=null}

接着,再试试创建的Employee对象,只给lastName一个属性赋值的情况

  1. @Test  
  2. public void testGetEmpsByConditionIf() throws IOException {  
  3.     SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();  
  4.     SqlSession openSession = sqlSessionFactory.openSession();  
  5.     try {  
  6.         EmployeeMapperDynamic mapper = openSession.getMapper(EmployeeMapperDynamic.class);  
  7.         Employee e = new Employee();  
  8.         e.setLastName("%青%");  
  9.         List<Employee> employeeList = mapper.getEmpsByConditionIf(e);  
  10.         for (Employee employee:employeeList){  
  11.             System.out.println(employee);  
  12.         }  
  13.     }finally {  
  14.         openSession.close();  
  15.     }  
  16. }  

结果:

报错!!!

分析一下,为什么?如果传入的Employee对象中没有id值,但是有lastName时,SQL语句会变成下面这个样子:

    select * from tb_employee and last_name like #{lastName}

显然是个有问题的查询语句,我们该如何解决这个问题?

我们可以将<select>查询中添加1=1,在之后的每个属性前都加上and XXXXXXX,就像下面这样:

  1. <select id="getEmpsByConditionIf" resultType="com.figsprite.bean.Employee">  
  2.     select * from tb_employee where 1=1  
  3.     
  4.     <if test="id!=null">  
  5.         and id = #{id}  
  6.     </if>  
  7.     <if test="lastName!=null and lastName!=""">  
  8.         and last_name like #{lastName}  
  9.     </if>  
  10.     <if test="email!=null and email.trim()!=""">  
  11.         and email = #{email}  
  12.     </if>  
  13.     <if test="gender==0 or gender==1">  
  14.         gender=#{gender}  
  15.     </if>  
  16.     
  17. </select>  

这显然没有问题,另外一种方法,MyBatis的<where>标签

where标签

使用方法很简单,将之前的<if>标签都包含在<where></where>之中即可

  1. <select id="getEmpsByConditionIf" resultType="com.figsprite.bean.Employee">  
  2.     select * from tb_employee  
  3.     <where>  
  4.         <if test="id!=null">  
  5.             and id = #{id}  
  6.         </if>  
  7.         <if test="lastName!=null and lastName!=""">  
  8.             and last_name like #{lastName}  
  9.         </if>  
  10.         <if test="email!=null and email.trim()!=""">  
  11.             and email = #{email}  
  12.         </if>  
  13.         <if test="gender==0 or gender==1">  
  14.             gender=#{gender}  
  15.         </if>  
  16.     </where>  
  17. </select> 
DEBUG [main] - ==>  Preparing: select * from tb_employee WHERE last_name like ?

可以发现<where>能将多余的and或者or去掉,当然where也有不好使的时候,有些人习惯将and放在后面,如下:

  1. <select id="getEmpsByConditionIf" resultType="com.figsprite.bean.Employee">  
  2.     select * from tb_employee  
  3.     <where>  
  4.         <if test="id!=null">  
  5.             and id = #{id} and  
  6.         </if>  
  7.         <if test="lastName!=null and lastName!=""">  
  8.             last_name like #{lastName} and  
  9.         </if>  
  10.         <if test="email!=null and email.trim()!=""">  
  11.             email = #{email} and  
  12.         </if>  
  13.         <if test="gender==0 or gender==1">  
  14.             gender=#{gender}  
  15.         </if>  
  16.     </where>  
  17. </select>  

DEBUG [main] - ==> Preparing: select * from tb_employee WHERE last_name like ? and

SQL语句明显出错,可见<where>只能去掉头部的and或者or

trim标签

如果我就想把and 放在后面,要怎么办?这是我们该用<trim>标签了,<trim>可以自定义截取标签

<trim>标签包含4个属性:

  1. 前缀:prefix
  2. 前缀覆盖:prefixOverrides
  3. 后缀:suffix
  4. 后缀覆盖:suffixOverrides

trim标签体中是整个字符串拼串后的结果,prefix给拼串后的整个字符串加一个前缀,比如我们可以不在SQL语句中写where而选择在<trim>中写:<trim prefix="where">……

前缀覆盖指的是去掉拼串前面多余的字符

后缀和后缀覆盖同理,那么我们在后面添加and就有可能出现后面多出and的情况,因此我们只要指定后缀覆盖的属性值为and,就可以处理上述情况:

  1. <select id="getEmpsByConditionTrim" resultType="com.figsprite.bean.Employee">  
  2.     select * from tb_employee  
  3.     <trim prefix="where" suffixOverrides="and">  
  4.         <if test="id!=null">  
  5.              id = #{id} and  
  6.         </if>  
  7.         <if test="lastName!=null and lastName!=""">  
  8.              last_name like #{lastName} and  
  9.         </if>  
  10.         <if test="email!=null and email.trim()!=""">  
  11.              email = #{email} and  
  12.         </if>  
  13.         <if test="gender==0 or gender==1">  
  14.              gender=#{gender}  
  15.         </if>  
  16.     </trim>  
  17. </select>  

DEBUG [main] - ==> Preparing: select * from tb_employee where last_name like ?

虽然看似功能强大的<trim>其实并不常用,大家作为了解即可

choose标签

这是一个分支选择标签,类似于Java中的switch-case,之前我们在<if>标签中是逐一判断哪个条件是合法存在的,然后使用该标签,接下来我们换一种要求,已知传入的Employee对象只会有一种属性是存在值的,那么我们就可以使用choose,当然也可以用if

    List<Employee> getEmpsByConditionChoose(Employee e);
  1. <select id="getEmpsByConditionChoose" resultType="com.figsprite.bean.Employee">  
  2.     select * from tb_employee  
  3.     <where>  
  4.         <choose>  
  5.             <when test="id!=null">  
  6.                 id=#{id}  
  7.             </when>  
  8.             <when test="lastName!=null and lastName!=""">  
  9.                 last_name like #{lastName}  
  10.             </when>  
  11.             <when test="email!=null and email.trim()!=""">  
  12.                 email = #{email}  
  13.             </when>  
  14.             <otherwise>  
  15.                 1=1  
  16.             </otherwise>  
  17.         </choose>  
  18.     </where>  
  19. </select>  

(其中test属性中的""要改成&quot;)

<otherwise>标签,就是当前面所有的when条件都没中的时候,拼接上这个标签里的语句

  1. @Test  
  2. public void testGetEmpsByConditionIf() throws IOException {  
  3.     SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();  
  4.     SqlSession openSession = sqlSessionFactory.openSession();  
  5.     try {  
  6.         EmployeeMapperDynamic mapper = openSession.getMapper(EmployeeMapperDynamic.class);  
  7.         Employee e = new Employee();  
  8.         e.setLastName("%青%");  
  9.         List<Employee> employeeList = mapper.getEmpsByConditionChoose(e);  
  10.         for (Employee employee:employeeList){  
  11.             System.out.println(employee);  
  12.         }  
  13.     }finally {  
  14.         openSession.close();  
  15.     }  

DEBUG [main] - ==> Preparing: select * from tb_employee WHERE last_name like ?

如果传入的对象同时包含id和lastName的话会查谁?显然是只会用id作为条件

动态SQL1的更多相关文章

  1. winform导入导出excel,后台动态添加控件

    思路: 导入: 1,初始化一个OpenFileDialog类 (OpenFileDialog fileDialog = new OpenFileDialog();) 2, 获取用户选择文件的后缀名(s ...

  2. jsp中使用动态数据进行mySQL数据库的两种操作方法

    使用动态数据进行数据库内容的增删改查操作有两种方法: 在此定义数据库连接为conn 假设有表单进行数据输入并提交到处理页面一种是使用预编译格式: 其格式如下: String name = reques ...

  3. 获取动态SQL的返回结果

    1. 介绍说明 有时候在执行存储过程后,需要获取存储过程返回的列表,然后进行相应操作的情况,或者执行动态语句,获取返回结果的情况,通过EXEC ,sp_executesql可以实现该功能. 网上也有很 ...

  4. mysql -- 动态获取结果集(重点)

    注意:语句传值的时候必须是带有@符号的参数,不能是自己的局部变量,一个@叫用户变量,两个@叫做全局变量.用户变量:当前用户的‘’全局变量‘’,用户状态存在时就存在,用户退出时消失. 初始版 delim ...

  5. mysql 字符串分割 和 动态执行拼接sql

    本人以前主要用的是MSSQL,最近项目在使用MYSQL,自己是一个 典型的小白.今天就记录一下 一个mysql存储过程,里面需要分割字符串和 动态执行sql语句. 关于字符串 分割我开始使用 LOCA ...

  6. Java动态菜单添加

    自己做出来的添加数据库配置好的动态菜单的方法 private void createMenu() {  IMenuDAO dao = new MenuDAOImpl();  String sql1 = ...

  7. sql的存储过程实例--动态根据表数据复制一个表的数据到另一个表

    动态根据表数据复制一个表的数据到另一个表 把track表的记录 根据mac_id后两位数字,复制到对应track_? 的表中 如:mac_id=12345678910,则后两位10 对应表为track ...

  8. mysql 存储过程动态执行sql语句

    之前经常在程序中拼接sql语句,其实我们也可以在存储过程中拼接sql 语句,动态的执行~~ 代码如下: DROP PROCEDURE IF EXISTS SearchByDoctor;CREATE P ...

  9. 在论坛中出现的比较难的sql问题:39(动态行转列 动态日期列问题)

    原文:在论坛中出现的比较难的sql问题:39(动态行转列 动态日期列问题) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所以,觉 ...

随机推荐

  1. Scrapy 框架 增量式

    增量式: 用来检测网站中数据的更新情况 from scrapy.linkextractors import LinkExtractor from scrapy.spiders import Crawl ...

  2. centos7下安装docker(17.2docker监控---weave scope)

    weave scope的最大的特点是会自动生成一张docker 容器地图,让我们能够直观的理解,监控和控制地图 先来感受一下(盗图) 1.安装 执行如下脚本安装运行weave scope  curl ...

  3. RocketMQ实现事务消息

    在RocketMQ4.3.0版本后,开放了事务消息这一特性,对于分布式事务而言,最常说的还是二阶段提交协议,那么RocketMQ的事务消息又是怎么一回事呢,这里主要带着以下几个问题来探究一下Rocke ...

  4. 发现电脑上装着liteide,就用golang做一个TCP通讯测试(支持先启动client端和断线重连)

    1.参考https://www.cnblogs.com/yin5th/p/9274495.html server端 main.go package main import ( "fmt&qu ...

  5. 003_python内置的@staticmethod详解

    python中的staticmethod 主要是方便将外部函数集成到类体中,美化代码结构,重点在不需要类实例化的情况下调用方法(类似java的静态方法) 如果你去掉staticmethod,在方法中加 ...

  6. Go web编程学习笔记——未完待续

    1. 1).GOPATH设置 先设置自己的GOPATH,可以在本机中运行$PATH进行查看: userdeMacBook-Pro:~ user$ $GOPATH -bash: /Users/user/ ...

  7. 阿里云轻量应用服务器debian8.9用apache多端口搭建多站点

    前几天想要再搭个网站玩玩,就用阿里的服务器,apache本地搭建站点和服务器相差不多,然而却踩了大坑,差点耗死在这儿. 先进入apache这个目录,有如下文件夹: 打开ports.conf,  添加 ...

  8. CF176E Archaeology

    CF176E Archaeology 有一棵 \(n\) 个点的带权树,每个点都是黑色或白色,最初所有点都是白色的.有 \(m\) 个询问: 把点 \(x\) 从白色变成黑色 把点 \(x\) 从黑色 ...

  9. org.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputException: Input length = 1

    项目启动报错2018-12-21 14:06:24.917 INFO 23472 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refr ...

  10. .Net Core 在 Linux-Centos上的部署实战教程(一)

    pa我是在VS2017上写好项目然后来部署的,我的宗旨能截图就少BB 服务器系统: Asp.Net Core版本: 1.往服务器安装.net core 2.1 https://www.microsof ...