上一章已经实现了最简单的CRUD的操作,不过还是有一些细节问题需要进一步的学习

一.#{}${}

在前面的章节中,大家已经看过很多次#()这个符号了,虽然没有专门的去讲解,但是也应该能猜出#{}应该就是一个参数的占位符,是的,大家猜测的没错,不过这个占位符除了#{}之外,还有一个${},两者都是起到占位的作用,但又是完全不同的.
简单来说, #{}其实就相当于我们之前在JDBC代码中使用了PreparedStatement,并在SQL语句中使用了 ? 替代符

${}的占位,就相当于SQL语句直接使用了字符串拼接,而且还需要自己加上``哦.

上面的意思我们用伪代码形容一下

select * from t_user where username=#{username}
就相当于
select * from t_user where username=?
而且会在随后的代码执行中自动用你传入的 `username` 参数将`?`替代掉,比如`username`的值是`张三`
select * from t_user where username='张三'select * from t_user where username=${username}
比如 参数 username 的值是张三,那就相当于
select * from t_user where username=张三
注意这里是错误的哦,因为张三是个字符串,你需要自己加上单引号
select * from t_user where username='${username}'才是正确的写法

所以,总结来说:#{}:解析为一个JDBC预编译语句(PreparedStatement)的参数标记,一个#()会被解析为一个参数占位符?,在数据库中发生参数的替换

${}: 仅仅为一个纯粹的String字符换的替换,而且在动态SQL的解析阶段就讲变量进行替换,而且如果参数就是一个简单类型的话(意思是不是一个自定义对象,就是一个int,或者String),那么参数的占位符只能使用value,也就是上面的 username=”张三”,如果就只有这么一个值,使用 ${} 替代符就只能使用value占位,也就是要写为 select * from t_user where username=${value}

因此一般情况下,我们当然优先使用#(),还能一定程度上防止SQL注入,但是有些时候使用${}却很方便,比如在模糊查询的时候

...
<!-- 根据名称模糊查询用户信息 -->
<select id="getUserByName" parameterType="string" resultMap="userMap">select * from t_user where username like '%${value}%'</select>
...

下面的截图,展示了上面文字描述的一些问题

二.动态SQL

上面的例子只是根据用户的名字进行了模糊查询,这个时候问题就来了,如果要使用多条件查询呢?那就需要用到MyBatis提供的动态SQL功能了,通过 if, choose, when, otherwise, trim, where, set, foreach标签,可组合成非常灵活的SQL语句

1. whereif

还是直接通过应用场景来解释,相信大家之前都写过多条件查询的SQL语句了,基本的思考点就是到底有哪些条件?哪些条件不为空的时候才进行SQL拼接?多条件后面的and或者or该怎么搞定?这个问题,在大家的学习过程中,最早期的代码应该是这么写的

......
String sql = "select * from t_user where 1=1 "
if(username != null && !"".equals(username)){sql += " and username like '%" + username + "%'";
}if(userTel != null && !"".equals(userTel)){sql += " and userTel ='" + userTel + "'";
}
...

在早期的JDBC代码中,为了避免SQL语句后面拼接and的问题,一般都会人为的在前面加上一个条件1=1,使用MyBatis其实也跳不过这个问题,不过我们使用MyBatis自带的标签来解决这个问题

<!--多条件查询动态SQL-->
<select id="getUserBySelective" parameterType="user" resultMap="userMap">select * from t_user    <where><if test="id >= 1">id=#{id}        </if><if test="userTel != null">and user_tel like '%${userTel}%'        </if><if test="username != null">and username like '%${username}%'        </if><if test="registrationTime != null">and Date_Format(registration_time,'%Y-%m-%d')=#{registrationTime}        </if></where>
</select>

上面的语句就用到了MyBatis的where和if标签,具体标签的含义其实不用多做解释大家也能看懂,而且最好的地方是完美的解决了之前and拼接的问题,下面的截图给大家展示了这些效果

2. trimif

where标签也完全可以用trim标签替代,一般情况下的写法是这个样子的

<trim prefix="WHERE" prefixOverrides="AND |OR ">...
</trim>

其实关键就是prefixprefixOverrides这两个属性prefix: 前缀,这里的意思就是SQL语句加上whereprefixOverrides: 去掉第一个and或者是or,就是后面的拼接语句中出现了and或者or,如果出现在第一个条件中就去掉

上面的代码,我们通过trim标签替换

<trim prefix="WHERE" prefixOverrides="AND |OR "><if test="id >= 1">id=#{id}    </if><if test="userTel != null">and user_tel like '%${userTel}%'    </if><if test="username != null">and username like '%${username}%'    </if><if test="registrationTime != null">and Date_Format(registration_time,'%Y-%m-%d')=#{registrationTime}    </if>
</trim>

3. setif

既然查询是多条件的,我们回过头看看之前写过的新增insert和修改update方法,按照之前的写法,如果有条件不传,会出现什么问题,我们看一下之前的修改方法

这样肯定和实际情况不符,我们新加一个修改方法,根据传入的值进行判断修改,这样改的关键点其实还是判断要修改的值是否为空,不为空再进行修改,问题的关键点还是多个条件判断的时候,最后一个逗号(,)截取的问题,在MyBatis中,使用set标签

同样,<trim>标签也可以完全替换<set>

<update id="updateUserByIdSelective" parameterType="user">update t_user  <trim prefix="set" suffixOverrides=","><if test="userTel != null">user_tel=#{userTel},      </if><if test="username != null">username=#{username},      </if><if test="password != null">password=md5(#{password}),      </if><if test="registrationTime != null">registration_time=#{registrationTime}      </if></trim>where id=#{id}
</update>

suffixOverrides: 去掉最后一个逗号(,)后缀

在新增语句中,也是一样,如果只是选择性的要插入一些字段(当然前提是数据库中该字段可以为null),看一下之前新增数据的效果

如果要选择性的拼接SQL,新增的SQL语句拼接会涉及到表字段,字段对应的值以及左括号,逗号,右括号,这样拼接判断的时候复杂度稍微高一些,所以,这里使用<trim>标签是最好的选择

<!--根据传入的参数新增用户信息-->
<insert id="insertUserSelective" parameterType="user" useGeneratedKeys="true" keyProperty="id">insert into t_user    <trim prefix="(" suffix=")" suffixOverrides="," ><if test="id != null" >id,        </if><if test="userTel != null">user_tel,        </if><if test="username != null" >username,        </if><if test="password != null" >password,        </if><if test="registrationTime != null" >registration_time,        </if></trim><trim prefix="values (" suffix=")" suffixOverrides="," ><if test="id != null" >#{id,jdbcType=INTEGER},        </if><if test="userTel != null" >#{userTel,jdbcType=VARCHAR},        </if><if test="username != null" >#{username,jdbcType=VARCHAR},        </if><if test="password != null" >md5(#{password,jdbcType=VARCHAR}),        </if><if test="registrationTime != null" >#{registrationTime,jdbcType=VARCHAR},        </if></trim>
</insert>

4. SQLinclude

有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。
比如上面新增语句的字段条件判断,插入语句实在写的太多,可以将这部分的代码提出来,直接写成代码片段,到时候再用<include>标签引用就可以了

这种用法特别是在写查询语句的时候,字段名较多的情况下,把经常要现实出来的字段用SQL标签引入,在写SQL语句的时候,再直接通过include引入字段就可以了

5. choose(when,otherwise)

上面的whereset标签都是在和if标签配合,判断标签除了if之外,还有choose(when,otherwise)标签,choose(when,otherwise)其实就类似于java的switch语句,把之前的查询语句,从where...if...的组合换成 where...choose(when,otherwise),但是要注意两者之间的区别,choose(when,otherwise)同时只能成立一个条件

<!--多条件查询动态SQL,使用where...choose(when...otherwise)组合-->
<select id="getUserBySelective2" parameterType="user" resultMap="userMap">select * from t_user    <where><choose><when test="id >= 1">id=#{id}            </when><when test="userTel != null">and user_tel like '%${userTel}%'            </when><when test="username != null">and username like '%${username}%'            </when><otherwise>and Date_Format(registration_time,'%Y-%m-%d')=#{registrationTime}            </otherwise></choose></where>
</select>

6. foreach

先来捋一捋代码场景,比如同时要查询多个值的场景,意思是SQL语句要写成类似于下面的这个样子:

select * from t_user where id=1 or id=4 or id=5 or id=8

或者

select * from t_user where id in(1, 4, 5, 8)

注意:
这个样子的SQL语句,为了传输值方便,不破坏User类,我们再封装一个Bean类,就叫做查询Bean,这个Bean就是为了查询而服务的,什么意思呢?界面上可能会有各种条件的查询,比如注册的开始日期,结束日期,根据这种情况进行查询,但是我们现在的User类其实只是完全和数据库对应的类,User类里只有一个注册日期,没有什么注册开始日期和结束日期的概念,但是在查询的时候却需要查询这些东西,所以干脆就专门建一个实体类,来处理封装界面上要查询的内容,这样就可以方便的将界面上的数据传输给Dao层.这其实是分层架构中VO,PO,DO,DTO等等领域模型的概念,有兴趣的可以自己查询了解一下

无论如果,为了封装方便,这里新创建一个类QueryBean.java:

//封装要查询的多个用户的id
import java.util.List;public class QueryBean {    private List<Integer> ids;    public List<Integer> getIds() {        return ids;}    public void setIds(List<Integer> ids) {        this.ids = ids;}
}

在UserMapper.xml中添加根据多个id查询的方法

<select id="getUserByQueryIds" parameterType="queryBean" resultMap="userMap">select * from t_user    <where><!--collection:指定输入对象中的集合属性item:每次遍历生成的对象open:开始遍历时的拼接字符串close:结束时拼接的字符串separator:遍历对象之间需要拼接的字符串select * from t_user where (id=1 or id=4 or id=5 or id=8)--><foreach collection="ids" item="id" open="(" close=")" separator="or">id=#{id}        </foreach></where>
</select>

注意下图中,foreach标签中每个属性的作用

也可以稍微换一种写法

<select id="getUserByQueryIds" parameterType="queryBean" resultMap="userMap">select * from t_user    <where><!--collection:指定输入对象中的集合属性item:每次遍历生成的对象open:开始遍历时的拼接字符串close:结束时拼接的字符串separator:遍历对象之间需要拼接的字符串select * from t_user where (id=1 or id=4 or id=5 or id=8)<foreach collection="ids" item="id" open="(" close=")" separator="or">id=#{id}</foreach>--><!-- select * from t_user where id in (1, 4, 5, 8) --><foreach collection="ids" item="id" open="id in (" close=")" separator=",">#{id}        </foreach></where>
</select>

oracle sql中查询语句where中字段不为空用if怎么写_MyBatis手把手跟我做系列(三) --- 动态SQL标签...相关推荐

  1. 如何在SQL Server查询语句(Select)中检索存储过程(Store Procedure)的结果集

    如何在SQL Server查询语句(Select)中检索存储过程(Store Procedure)的结果集?(2006-12-14 09:25:36) 与这个问题具有相同性质的其他描述还包括: 如 ...

  2. Oracle数据库里面查询字符串类型的字段不为空和为空的SQL语句:

    摘要:近期项目中,在做高级查询的时候有个条件是根据选择的字段,然后再选择字段的值为空和不为空做查询,在写SQL语句的时候费了很长时间,现在记录一下,方便日后查看: 一:查询字符串类型的字段的值不为空的 ...

  3. jpa mysql sql分页查询语句_jpa 中 Query 的分页查询和更新

    1,查询分页 注意这个地方nativeQuery=true 代表的是可执行原生sql 先查询出来所有的数据,然后再差个总条数 返回page @Query(nativeQuery = true, val ...

  4. mybatis 三级缓存查询循序_MyBatis手把手跟我做系列(五) --- 一级缓存与二级缓存

    一.什么是缓存 要理解MyBatis的一级缓存,至少,你需要先直接什么是缓存的这个概念,其实我们一直都在用 直接来看下面的图: 对于我们之前的JDBC操作,如果需要连续请求id=1的用户数据,那么就需 ...

  5. mysql 在sql查询语句结果中,数字加千分逗号

    mysql 在sql查询语句结果中,数字加千分逗号 FORMAT(X,D) 将number X设置为格式 '#,###,###.##', 以四舍五入的方式保留到小数点后D位, 而返回结果为一个字符串. ...

  6. sql中查询当天时间和判断参数为空的坑

    sql中查询当天时间和判断参数为空的坑 根据时间查询的时候,如何查询当天 Mysql将参数为0的数,也归纳到 ' ' 中: # 实例: 根据时间查询的时候,如何查询当天 查询当天时间内的数据时,需要注 ...

  7. 企业实战07:Oracle数据库_查询语句

    Oracle数据库专栏 命令后面可以不加;分号 SQL语句后面一定要加;分号 文章目录 查询语句 6-1 Oracle 查询概述 6-2 Oracle 基本查询语句 6-3 Oracle查询语句之在s ...

  8. sql嵌套查询返回多个字段_list4 SQL复杂查询

    子查询返回结果形式不同: 标量子查询(结果集只有一行一列) 列子查询(结果集只有一列多行) 行子查询(结果集有一行多列) 表子查询(结果集一般为多行多列) 子查询在主查询中出现的位置不同: selec ...

  9. SQL 分页查询语句大全即(查找第N到M条记录的方法)

    SQL 分页查询语句大全即(查找第N到M条记录的方法) 第一种方法,我的原创方法 row=2 表示分页行数 page=1 表示页码 getnum=row*page select * from  (se ...

  10. MySQL学习记录 (二) ----- SQL数据查询语句(DQL)

    相关文章: <MySQL学习记录 (一) ----- 有关数据库的基本概念和MySQL常用命令> <MySQL学习记录 (二) ----- SQL数据查询语句(DQL)> &l ...

最新文章

  1. 遥感图像+CNN,预测区域人口收入水平
  2. 使用webpack打包后,vscode中vue代码变白色的解决办法
  3. 参加第十六届智能车竞赛同学提问与回答-6-30
  4. python 3.9 新特性 简介
  5. 计算机网络·“存储-转发”式分组交换网
  6. 02.centos6.4找不到ifcfg-eth0(静态ip配置)
  7. DataTable的Ajax使用
  8. war包部署-打包测试
  9. selenium基础入门
  10. Opencv--CvMat声明和使用
  11. (十六)java中的String
  12. sql server 数组_如何在SQL Server中实现类似数组的功能
  13. 人脸关键点:MTCNN-Joint Face Detection and Alignment using Multi-task Cascaded Convolutional Networks
  14. 洛谷 P1558 色板游戏
  15. 网易云信 web demo体验-会议
  16. mysql中status状态说明
  17. 超级计算机神威太湖之光储蓄量,中国超级计算机神威太湖之光世界最快,且总量排名榜单第一...
  18. Frenet坐标系与Cartesian坐标系互转(二):Python代码函数实现
  19. 计算机网络基础教程实训总结,实训总结
  20. windows 下 安装python以及scrapy 环境

热门文章

  1. 树莓派(Raspberry Pi)日期时间不准的修正方法
  2. linux中 ECShop的文件不能写
  3. 4月26 simulink数据input,与全局变量建立堆栈
  4. 深入解构magnitude_spectrum()
  5. Mysql优化(出自官方文档) - 第二篇
  6. ZStack源码剖析之核心库鉴赏——Defer
  7. [Linux] PHP程序员玩转Linux系列-Nginx中的HTTPS
  8. 基于itchat实现微信群消息同步机器人
  9. python selenium --鼠标事件
  10. 【原创】Kakfa log包源代码分析(一)