动态SQL1
If标签
动态SQL可以说是MyBatis最强大之处了,这块的应用主要有四个方面if,choose,trim和foreach,接下来先说说if。
顾名思义,if是用来判断条件的,现在假设我们有个需求,原先我们查询员工是靠id查询的,现在提出新的要求,要求用户输入携带了哪个字段查询条件就带上这个字段的值,
- List<Employee> getEmpsByConditionIf(Employee e);
那么这个sql语句该怎么写呢?
- <select id="EmployeeMapperDynamicTest" resultType="com.figsprite.bean.Employee">
- select * from tb_employee where id = #{id} and last_name like #{lastName}
- and email = #{email} and gender=#{gender}
- </select>
这种写法显然是有问题的,如果传入的Employee中lastName为空,这个select语句就查不出我们想要的结果,还有很多类似的情况,此时,就要使用到if,<if test=""></if>,test属性中采用的是OGNL表达式,与EL表达式和你像,大家可以去官网查找具体的内容[http://commons.apache.org/proper/commons-ognl/download_ognl.cgi]
在书写test属性中的OGNL时要注意遇到特殊符号应该写转移字符,比如&要写成&;
具体的对应关系可以查找W3C的手册:
[https://www.w3cschool.cn/htmltags/ref-entities.html]
- <select id="getEmpsByConditionIf" resultType="com.figsprite.bean.Employee">
- select * from tb_employee
- <if test="id!=null">
- id = #{id}
- </if>
- <if test="lastName!=null and lastName!=""">
- and last_name like #{lastName}
- </if>
- <if test="email!=null and email.trim()!=""">
- and email = #{email}
- </if>
- <if test="gender==0 or gender==1">
- gender=#{gender}
- </if>
- </select>
注意两点1.email判断时用到了email.trim() 2.gender原本是字符串,可此处将它当做是是数字,OGNL会进行字符串与数字的转化判断.
做一下测试:
- public static SqlSessionFactory getSqlSessionFactory() throws IOException {
- String resource = "mybatis-conf.xml";
- InputStream inputStream = Resources.getResourceAsStream(resource);
- return new SqlSessionFactoryBuilder().build(inputStream);
- }
- @Test
- public void testGetEmpsByConditionIf() throws IOException {
- SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
- SqlSession openSession = sqlSessionFactory.openSession();
- try {
- EmployeeMapperDynamic mapper = openSession.getMapper(EmployeeMapperDynamic.class);
- Employee e = new Employee();
- e.setId(5);
- e.setLastName("%青%");
- List<Employee> employeeList = mapper.getEmpsByConditionIf(e);
- for (Employee employee:employeeList){
- System.out.println(employee);
- }
- }finally {
- openSession.close();
- }
- }
结果:Employee{id=5, lastName='吴青宁', gender='1', email='wq', department=null}
接着,再试试创建的Employee对象,只给lastName一个属性赋值的情况
- @Test
- public void testGetEmpsByConditionIf() throws IOException {
- SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
- SqlSession openSession = sqlSessionFactory.openSession();
- try {
- EmployeeMapperDynamic mapper = openSession.getMapper(EmployeeMapperDynamic.class);
- Employee e = new Employee();
- e.setLastName("%青%");
- List<Employee> employeeList = mapper.getEmpsByConditionIf(e);
- for (Employee employee:employeeList){
- System.out.println(employee);
- }
- }finally {
- openSession.close();
- }
- }
结果:
报错!!!
分析一下,为什么?如果传入的Employee对象中没有id值,但是有lastName时,SQL语句会变成下面这个样子:
select * from tb_employee and last_name like #{lastName}
显然是个有问题的查询语句,我们该如何解决这个问题?
我们可以将<select>查询中添加1=1,在之后的每个属性前都加上and XXXXXXX,就像下面这样:
- <select id="getEmpsByConditionIf" resultType="com.figsprite.bean.Employee">
- select * from tb_employee where 1=1
- <if test="id!=null">
- and id = #{id}
- </if>
- <if test="lastName!=null and lastName!=""">
- and last_name like #{lastName}
- </if>
- <if test="email!=null and email.trim()!=""">
- and email = #{email}
- </if>
- <if test="gender==0 or gender==1">
- gender=#{gender}
- </if>
- </select>
这显然没有问题,另外一种方法,MyBatis的<where>标签
where标签
使用方法很简单,将之前的<if>标签都包含在<where></where>之中即可
- <select id="getEmpsByConditionIf" resultType="com.figsprite.bean.Employee">
- select * from tb_employee
- <where>
- <if test="id!=null">
- and id = #{id}
- </if>
- <if test="lastName!=null and lastName!=""">
- and last_name like #{lastName}
- </if>
- <if test="email!=null and email.trim()!=""">
- and email = #{email}
- </if>
- <if test="gender==0 or gender==1">
- gender=#{gender}
- </if>
- </where>
- </select>
DEBUG [main] - ==> Preparing: select * from tb_employee WHERE last_name like ?
可以发现<where>能将多余的and或者or去掉,当然where也有不好使的时候,有些人习惯将and放在后面,如下:
- <select id="getEmpsByConditionIf" resultType="com.figsprite.bean.Employee">
- select * from tb_employee
- <where>
- <if test="id!=null">
- and id = #{id} and
- </if>
- <if test="lastName!=null and lastName!=""">
- last_name like #{lastName} and
- </if>
- <if test="email!=null and email.trim()!=""">
- email = #{email} and
- </if>
- <if test="gender==0 or gender==1">
- gender=#{gender}
- </if>
- </where>
- </select>
DEBUG [main] - ==> Preparing: select * from tb_employee WHERE last_name like ? and
SQL语句明显出错,可见<where>只能去掉头部的and或者or
trim标签
如果我就想把and 放在后面,要怎么办?这是我们该用<trim>标签了,<trim>可以自定义截取标签
<trim>标签包含4个属性:
- 前缀:prefix
- 前缀覆盖:prefixOverrides
- 后缀:suffix
- 后缀覆盖:suffixOverrides
trim标签体中是整个字符串拼串后的结果,prefix给拼串后的整个字符串加一个前缀,比如我们可以不在SQL语句中写where而选择在<trim>中写:<trim prefix="where">……
前缀覆盖指的是去掉拼串前面多余的字符
后缀和后缀覆盖同理,那么我们在后面添加and就有可能出现后面多出and的情况,因此我们只要指定后缀覆盖的属性值为and,就可以处理上述情况:
- <select id="getEmpsByConditionTrim" resultType="com.figsprite.bean.Employee">
- select * from tb_employee
- <trim prefix="where" suffixOverrides="and">
- <if test="id!=null">
- id = #{id} and
- </if>
- <if test="lastName!=null and lastName!=""">
- last_name like #{lastName} and
- </if>
- <if test="email!=null and email.trim()!=""">
- email = #{email} and
- </if>
- <if test="gender==0 or gender==1">
- gender=#{gender}
- </if>
- </trim>
- </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);
- <select id="getEmpsByConditionChoose" resultType="com.figsprite.bean.Employee">
- select * from tb_employee
- <where>
- <choose>
- <when test="id!=null">
- id=#{id}
- </when>
- <when test="lastName!=null and lastName!=""">
- last_name like #{lastName}
- </when>
- <when test="email!=null and email.trim()!=""">
- email = #{email}
- </when>
- <otherwise>
- 1=1
- </otherwise>
- </choose>
- </where>
- </select>
(其中test属性中的""要改成")
<otherwise>标签,就是当前面所有的when条件都没中的时候,拼接上这个标签里的语句
- @Test
- public void testGetEmpsByConditionIf() throws IOException {
- SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
- SqlSession openSession = sqlSessionFactory.openSession();
- try {
- EmployeeMapperDynamic mapper = openSession.getMapper(EmployeeMapperDynamic.class);
- Employee e = new Employee();
- e.setLastName("%青%");
- List<Employee> employeeList = mapper.getEmpsByConditionChoose(e);
- for (Employee employee:employeeList){
- System.out.println(employee);
- }
- }finally {
- openSession.close();
- }
- }
DEBUG [main] - ==> Preparing: select * from tb_employee WHERE last_name like ?
如果传入的对象同时包含id和lastName的话会查谁?显然是只会用id作为条件
动态SQL1的更多相关文章
- winform导入导出excel,后台动态添加控件
思路: 导入: 1,初始化一个OpenFileDialog类 (OpenFileDialog fileDialog = new OpenFileDialog();) 2, 获取用户选择文件的后缀名(s ...
- jsp中使用动态数据进行mySQL数据库的两种操作方法
使用动态数据进行数据库内容的增删改查操作有两种方法: 在此定义数据库连接为conn 假设有表单进行数据输入并提交到处理页面一种是使用预编译格式: 其格式如下: String name = reques ...
- 获取动态SQL的返回结果
1. 介绍说明 有时候在执行存储过程后,需要获取存储过程返回的列表,然后进行相应操作的情况,或者执行动态语句,获取返回结果的情况,通过EXEC ,sp_executesql可以实现该功能. 网上也有很 ...
- mysql -- 动态获取结果集(重点)
注意:语句传值的时候必须是带有@符号的参数,不能是自己的局部变量,一个@叫用户变量,两个@叫做全局变量.用户变量:当前用户的‘’全局变量‘’,用户状态存在时就存在,用户退出时消失. 初始版 delim ...
- mysql 字符串分割 和 动态执行拼接sql
本人以前主要用的是MSSQL,最近项目在使用MYSQL,自己是一个 典型的小白.今天就记录一下 一个mysql存储过程,里面需要分割字符串和 动态执行sql语句. 关于字符串 分割我开始使用 LOCA ...
- Java动态菜单添加
自己做出来的添加数据库配置好的动态菜单的方法 private void createMenu() { IMenuDAO dao = new MenuDAOImpl(); String sql1 = ...
- sql的存储过程实例--动态根据表数据复制一个表的数据到另一个表
动态根据表数据复制一个表的数据到另一个表 把track表的记录 根据mac_id后两位数字,复制到对应track_? 的表中 如:mac_id=12345678910,则后两位10 对应表为track ...
- mysql 存储过程动态执行sql语句
之前经常在程序中拼接sql语句,其实我们也可以在存储过程中拼接sql 语句,动态的执行~~ 代码如下: DROP PROCEDURE IF EXISTS SearchByDoctor;CREATE P ...
- 在论坛中出现的比较难的sql问题:39(动态行转列 动态日期列问题)
原文:在论坛中出现的比较难的sql问题:39(动态行转列 动态日期列问题) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所以,觉 ...
随机推荐
- 【HNOI2016】大数
[HNOI2016]大数 题目链接 题目描述 小 B 有一个很大的数 $ S $,长度达到了 $ N $ 位:这个数可以看成是一个串,它可能有前导 $ 0 $,例如 00009312345 .小 B ...
- Matplotlib 绘图 用法
Matplotlib基础知识 一.Matplotlib基础知识 Matplotlib中的基本图表包括的元素 x轴和y轴 axis 水平和垂直的轴线 x轴和y轴刻度 tick 刻度标示坐标轴的分隔,包括 ...
- go基础之数组和切片
数组 数组的定义: 数组是具有固定长度并拥有零个或者多个相同数据类型元素的序列 定义一个数组的方法:var 变量名[len] type 例子:var a[5] int //3个整数的数组var a[5 ...
- (predicted == labels).sum().item()作用
⚠️(predicted == labels).sum().item()作用,举个小例子介绍: # -*- coding: utf-8 -*-import torch import numpy as ...
- hyperledger中文文档学习-2-简介
参考https://hyperledgercn.github.io/hyperledgerDocs/blockchain_zh/ Hyperledger区块链框架(https://blog.csdn. ...
- [Spark][kafka]kafka 生产者,消费者 互动例子
[Spark][kafka]kafka 生产者,消费者 互动例子 # pwd/usr/local/kafka_2.11-0.10.0.1/bin 创建topic:# ./kafka-topics.sh ...
- 蓝牙BLE设备主机重启回连流程分析
如果一个BLE设备已经与蓝牙中心设备连接上,那么当中心设备的断电重启,其依然会和配对过的BLE设备连接上,而不需要重新走配对的流程,这个过程叫做回连. 这篇文章就分析一下当中心设备断电重启之后,其与B ...
- 【NLP】Attention Model(注意力模型)学习总结
最近一直在研究深度语义匹配算法,搭建了个模型,跑起来效果并不是很理想,在分析原因的过程中,发现注意力模型在解决这个问题上还是很有帮助的,所以花了两天研究了一下. 此文大部分参考深度学习中的注意力机制( ...
- 解决React通过ajax加载数据更新页面不加判断会报错的问题
通过AJAX加载数据是一个很普遍的场景.在React组件中如何通过AJAX请求来加载数据呢?首先,AJAX请求的源URL应该通过props传入:其次,最好在componentDidMount函数中加载 ...
- prometeus, grafana部署以及监控mysql
什么是普罗米修斯? Prometheus是一个最初在SoundCloud上构建的开源系统监视和警报工具包 .自2012年成立以来,许多公司和组织都采用了Prometheus,该项目拥有一个非常活跃的开 ...