4. 动态SQL及SQL片段

4.1 if

<if test="条件">拼接的sql</if>

Mybatis中的if标签用于拼接sql。例如:

<select id="getEmployees" parameterType="Employee" resultMap="employeeMap">select * from EMPLOYEEwhere ID=#{id} and NAME like  CONCAT('%', #{name},'%')
</select>

如果id和name两个条件要动态组合,即有时需要根据id查询,有时需要根据name查询,有时要id和name一起插查询。如果写三个语句会大大降低开发效率,增加代码冗余。如果需要动态组合的条件更多,那么开发人员将要写无数种情况的语句。

这时,可以使用if标签进行动态sql的生成:

<select id="getEmployees" parameterType="Employee" resultMap="employeeMap">select * from EMPLOYEEwhere<if test="id!=null"> ID=#{id}</if><if test="name!=null and name !=''"> and NAME like CONCAT('%', #{name},'%')</if>
</select>

当test的条件满足的时候,标签中包含的语句会拼接到前面的sql中。

·判断数值类型、日期类型不为空,可以直接使用“属性!=null”来判断。

·判断字符串类型不为空,除了判断不为null意外,还要判断不等于空字符串。

上面的例子中,如果id和name都不为空,则生成的语句是:

select * from EMPLOYEE where ID=? and NAME like CONCAT(’%’, #{name},’%’)

如果id不为空,name为空,则生成的语句是:

select * from EMPLOYEE where ID=?

但如果id和name都为空,生成的语句就是:

select * from EMPLOYEE where

这是一个不完整的sql。这时就需要用到where或trim标签。

4.2 where

where标签可以根据条件,决定是否拼接where关键字,并且能动态处理近邻where后的and或or关键字:

<select id="getEmployees" parameterType="Employee" resultMap="employeeMap">select * from EMPLOYEE<where><if test="id!=null">ID=#{id}</if><if test="name!=null and name !=''">and NAME like CONCAT('%', #{name},'%')</if></where>
</select>

如果id和name都为空,生成语句是:
select * from EMPLOYEE

如果id为空,name有值,where会自动把and NAME like CONCAT(’%’, #{name},’%’)前面的and去掉,生成的语句是:
select * from EMPLOYEE where NAME like CONCAT(’%’, ?,’%’)

4.3 set

set标签用于update语句中。

<update id="updateEmployee" parameterType="Employee">update EMPLOYEEset<if test="name!=null and name !=''">NAME =#{name},</if><if test="salary!=null">SALARY =#{salary}</if>where ID=#{id}
</update>

上面的语句,当name!=null而salary==null的时候,生成的语句是:
update EMPLOYEE set name=?, where ID=?
执行的时候会报错,原因是where前面多了一个逗号。
使用set标签:

<update id="updateEmployee" parameterType="Employee">update EMPLOYEE<set><if test="name!=null and name !=''">NAME =#{name},</if><if test="salary!=null">SALARY =#{salary},</if></set>where ID=#{id}
</update>

当name为空而salary不为空的时候,生成的语句是:
update EMPLOYEE set salary=? where ID=?

set标签可以动态设置set关键字,并且智能消除无关的逗号。
但是当set中所有的if条件都不满足的时候(name和salary都为空),生成的语句是:
update EMPLOYEE set where ID=?
这是个错误的语句,程序会报错。

从业务逻辑上讲,需要执行update更新的时候却一个属性都不赋值,本身就是不对的。所以可以在程序中捕捉到异常并提示用户更新失败。如果不想捕捉异常也不想判断所有的属性,可以加上ID字段:

<update id="updateEmployee" parameterType="Employee">update EMPLOYEE<set><if test="name!=null and name !=''">NAME =#{name},</if><if test="salary!=null">SALARY =#{salary},</if></set>ID=#{id}where ID=#{id}
</update>

4.4 trim

trim标签可以用来替代where和set标签。
使用trim代替where:

<select id="getEmployees2" parameterType="Employee" resultMap="employeeMap">select * from EMPLOYEE<trim prefix="WHERE" prefixOverrides="AND |OR "><if test="id!=null">ID=#{id}</if><if test="name!=null and name !=''">and NAME like CONCAT('%', #{name},'%')</if></trim>
</select>

prefix=”WHERE”是拼接where关键字,prefixOverrides=”AND | OR ”是如果where后紧邻and或or的时候智能的去掉。注意AND和OR后面都有个空格。

使用trim代替set:

<update id="updateEmployee2" parameterType="Employee">update EMPLOYEE<trim prefix="SET" suffixOverrides=","><if test="name!=null and name !=''">NAME =#{name},</if><if test="salary!=null">SALARY =#{salary},</if></trim>where ID=#{id}
</update>

4.5 choose,when,otherwise

choose,when,otherwise三个标签要结合到一起使用:

<select id="getEmployees3" parameterType="Employee" resultMap="employeeMap">select * from EMPLOYEE<trim prefix="WHERE" prefixOverrides="AND |OR "><choose><when  test="id!=null">ID=#{id}</when ><when  test="name!=null and name !=''"> NAME =#{name}</when ><when  test="salary!=null">SALARY=#{salary}</when ><otherwise > DEPT_ID=1</otherwise></choose></trim>
</select>

choose-when和if标签的区别是,一个choose中有多个when,从上至下,如果第一个when条件满足,则只拼接这个when中的语句,后面的when和otherwise都跳过不判断了也不拼接。如果第一个when不满足,就判断第二个,依次类推。如果所有的when都不满足,就拼接otherwise中的语句。

即多个if标签,彼此之间都是独立的,互不影响。而choose-when标签中,多个when只能满足一个,从上至下判断,找到第一个匹配的条件后,剩余的when都不再进行匹配。

4.6 foreach

foreach通常用在构建IN的查询条件:

<select id="getEmployees4" parameterType="List" resultMap="employeeMap">select * from EMPLOYEEwhere ID IN<foreach collection="list" index="index" item="item" open="(" separator="," close=")">#{item}</foreach>
</select>

foreach用于遍历collection中指定的集合open和close指定前后拼接的字符,separator是集合元素间插入的符号。

上面的语句如果传入一个包含3个元素的List,生成的语句是:

select * from EMPLOYEE where ID IN ( ? , ? , ? )

·如果parameterType类型是List,则collection=list

·如果parameterType类型是ArrayList(数组), 则collection=array

·如果parameterType是自定义的实体类,而类中有个集合属性, 则collection=集合属性名

4.7 bind

bind可以创建一个变量,并绑定到上下文,如

<select id="getEmployees5" parameterType="Employee" resultMap="employeeMap"><bind name="pattern" value="'%' + name+ '%'" />select * from EMPLOYEEwhereNAME like #{pattern}
</select>

上面的代码,bind标签将name的前后拼接了%并赋值给了pattern

如果传入的name=张,生成的语句为:
select * from EMPLOYEE where NAME like ?

?的值会替换为“%张%”

4.8 sql,include

sql标签可以把可复用的语句提取出来,通过include语句引用它。

比如前面的示例中,很多地方都用到了select * from EMPLOYEE,我们就可以把它提取出来:

<sql id="selectEmployee">select * from EMPLOYEE
</sql><select id="getEmployees6" parameterType="int" resultMap="employeeMap"><include refid="selectEmployee"/>where ID =#{id}
</select>

5. 补充

5.1 _parameter

<select id="getDeptById" parameterType="int" resultMap="deptMap">select ID,NAME from DEPT where ID=#{id}</select>

在标签中,parameterType传递基本数据类型的时候,可以给参数取任意的名字,如此处可以用#{id},#{abc},#{xxx}都可以。

但是当使用判断test条件的时候,就需要使用_parameter作为参数名,如:

<select id="getDeptById" parameterType="int" resultMap="deptMap">select ID,NAME from DEPT<if test="_parameter!=null"> where ID=#{id}</if>
</select>

如果写成下面的形式,就会报错:

<select id="getDeptById" parameterType="int" resultMap="deptMap">select ID,NAME from DEPT<if test="id!=null"> where ID=#{id}</if>
</select>
org.apache.ibatis.exceptions.PersistenceException: \### Error querying database.  Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'id' in 'class java.lang.Integer'\### Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'id' in 'class java.lang.Integer'

5.2 #{}和${}

#{}是将传入的值当做字符串的形式,并且有预编译功能。

${}是将传入的数据直接显示生成sql语句。假设现在参数name的值是abc

select * from DEPT where name=#{name} 会预编译成select * from DEPT where ID=?。执行的时候给?赋值,实际执行的语句是:select * from DEPT where name=’abc’。注意’abc’外面有个引号,它是字符串形式。

select * from DEPT where name=${name}没有预编译功能,直接生成:

select * from DEPT where name=abc。

#方式能够很大程度防止sql注入,方式无法防止Sql注入。方式无法防止Sql注入。方式无法防止Sql注入。方式一般用于传入数据库对象,例如传入表名、列名。 一般能用#的就别用$。

如果MyBatis排序时需要动态改变order by 的排序字段,使用order by 动态参数时需要注意,用$而不是#。ORDER BY ${columnName}。

动态SQL及SQL片段、_parameter、#{}和${}的区别相关推荐

  1. MyBatis总结七:动态sql和sql片段

    开发中,sql拼接很常见,所以说一下动态sql: 1 if 2 chose,when,otherwise 3 where,set 4 foreach 用法解析(现有一张users表 内有id user ...

  2. Java获取Mybatis动态生成的sql

    前提:已经编写好相应的接口个xml文件 public void exportExcel_bw() throws Exception {//封装sql需要查询的sql的条件Map<String, ...

  3. 批处理写入以及动态与参数化SQL,数据库的性能如何?

    批处理写入是最有效的数据库优化之一. 批处理写入受大多数现代数据库和JDBC标准的一部分支持,并且受大多数JPA提供程序支持. 普通数据库访问包括在单独的数据库/网络访问中将每个DML(插入,更新,删 ...

  4. sql server 监视_使用动态管理对象监视SQL Server –请求

    sql server 监视 In my last post, Monitoring SQL Server with dynamic management objects – Sessions and ...

  5. sql server 监视_使用动态管理对象监视SQL Server –会话和连接

    sql server 监视 A fundamental task of Database Administrators is monitoring SQL Server performance. Wh ...

  6. 动态SQL与SQL注入(一)动态SQL

    SQL Server提供了2个用于执行动态构造的代码字符串命令,分别为exec和sp_executesql. Exec 有两种用法:一种是执行一个存储过程. 表结构及测试数据如下: create ta ...

  7. SQL Server 中 EXEC 与 SP_EXECUTESQL 的区别

    SQL Server 中 EXEC 与 SP_EXECUTESQL 的区别 原文:SQL Server 中 EXEC 与 SP_EXECUTESQL 的区别 MSSQL为我们提供了两种动态执行SQL语 ...

  8. SQL注入——SQL注入漏洞利用(零)(值得收藏)

    一.什么是SQL注入漏洞 攻击者利用Web应用程序对用户输入验证上的疏忽,在输入的数据中包含对某些数据库系 统有特殊意义的符号或命令,让攻击者有机会直接对后台数据库系统下达指令,进而实现对后 台数据库 ...

  9. SQL注入(SQL Injection)

    简介 SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据 ...

最新文章

  1. mysql yearweek 日期不准_Mysql 中,WEEK 与YEARWEEK函数的参数问题
  2. apache修改最大连接并用ab网站压力测试
  3. 用户研究,你还在“凭感觉”吗?
  4. python pandas 数据透视表_python – Pandas数据透视表:列顺序和小计
  5. 粗读《构建之法》后的思考和收获
  6. 基于Docker搭建GitLab代码管理
  7. php怎么加编码,php怎么设置编码格式
  8. 股票和基金,哪个适合打工族?
  9. 学习Kubernetes 和容器技术体系的最佳方法
  10. 路径规划之DWA类算法简述
  11. AcWing 1843. 圆形牛棚(暴力+枚举)
  12. 【bzoj2434】[Noi2011]阿狸的打字机【AC自动机】
  13. 数据库操作之——约束
  14. sql查询数据库所有表(select * from sysobjects )
  15. 【今日CV 计算机视觉论文速览 第144期】Wed, 17 Jul 2019
  16. 2022年10月17日【Jiawei_Z】WPF的容器章节
  17. hfs支持php文件系统,HFS+文件系统的发展及特点介绍
  18. 在 EXCEL 中,“插入已剪切单元格”的快捷键
  19. getPhoneNumber:fail no permission
  20. 八一钢铁:宝钢入主,中报业绩大幅增长

热门文章

  1. windows下cmd中命令操作
  2. Eclipse+Pydev环境搭建
  3. Python系列之入门篇——HDFS
  4. MQTT的学习之Mosquitto安装使用(1)
  5. java 中的this
  6. Android 注解的使用与注意事项
  7. iOS 对arc的一点深入理解
  8. Hihocoder 最近公用祖先三 在线LCA
  9. JavaScript 电话手机号码正则表达式
  10. JavaScript(四)—— JavaScript 内置对象/JavaScript 简单数据类型与复杂类型