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. 为什么阿里如此钟爱Flink?
  2. python os模块system_python 中 os.system 的本质 | 编程知识2
  3. c#求三角形面积周长公式_此题要求三角形的面积,但是无法用公式求出,而是通过方程解决...
  4. 脑洞大开!20幅漫画告诉你未来世界是怎样的
  5. 大学学了一个学期的 C 语言,我们应该明白哪些知识点?别像没学一样!
  6. python串口数据分包_python TCP Socket的粘包和分包的处理详解
  7. WINDOWS 下将 FAT OR FAT32 转换成 NTFS 格式
  8. java+swing+mysql员工工资管理系统设计分析
  9. Google OKR 目标管理体系学习
  10. 完全删除conime.exe
  11. 无法定位序数1上的动态链接库
  12. 台达DVP-ES3 ModbusTCP通信案例
  13. ROS实验笔记之——基于ArUco Marker来估算camera的位姿
  14. java setpriority_Java Thread setPriority()方法
  15. Android BLE操作成功或失败status code对应解释
  16. Redis RDB和AOF
  17. 利用STM32CubeMX软件生成USB_DEVICE_SD卡虚拟U盘
  18. Java-超市购物小票案例-详细介绍
  19. Mol Cell Proteomics. |陈洁| 整合鸟枪法蛋白质组学中鉴定和定量的错误率
  20. 视频直播网站源码,uniapp页面跳转的几种方法和区别

热门文章

  1. Spring —— context:property-placeholder/元素
  2. MYSQL 学习笔记记录整理之三:子查询
  3. python文件,字符串,二进制的读写
  4. 20145203盖泽双《网络对抗技术》拓展:注入:shellcode及return-into-libc攻击
  5. DataTable筛选某列最大值
  6. 技能系统设计笔记 3
  7. axios的请求配置
  8. 生物医学基础--讲不明白12导联算我输
  9. zouxy09博客原创性博文导航
  10. php时间函数单字母,ThinkPhp单字母函数