1、bind标签
- bind 标签可以使用 OGNL 表达式创建一个变量井将其绑定到上下文中
语法:
<bind name = "需要绑定的变量" value = "绑定的最终值" />
- name:为上下文的变量,如SQL中存在#{userName}变量,这里name就填写userName
- value:绑定变量的最终值,如name="userName",那么value就是#{userName}的最终实际值,可以对传递的参数进行处理,如:value = " '%' + userName + '%' ",给传入的userName拼接前后%符号。
2、作用
1>兼容不同数据库之间的SQL语法差异,对数据库迁移友好
由于不同数据库的部分SQL写法存在差异,使用bind可以适配不同数据库之间的差异
如:模糊查询时,使用concat字符串拼接函数,在MySQL中支持多个参数,而Oracle中只能写两个参数,如下:
MySQL写法:
select id,serial from payment
where
serial like concat("%",#{serial},"%")
Oracle写法:
select id,serial from payment
where
serial like concat("%",concat(#{serial},"%"))
因此,在Oracle迁移至MySQL时,会导致mybatis报错,我们可以使用bind标签直接兼容,如下:
select id,name from payment
where
<bind name="name" value="'%'+name+'%'" />
name like #{name} --name实际是bind标签中的value
2>防止SQL注入
以模糊查询为例,当我们不使用concat函数,直接使用SQL字符串拼接时,如下:
select id,serial from payment
where
serial like "%${serial}%"
--注意:Oracle写法为:"%"||${serial}||"%"
注意:这里只能为:"%${serial}%",不能是"%#{serial}%"
- "%${serial}%":${serial}会看成字符串占位符,当运行SQL时直接替换该部分
- "%#{serial}%":#{serial}在字符串拼接时,不会生效,直接就是一个"%#{serial}%"字符串
我们测试上述SQL模糊查询语句,SQL注入案例:
<1>MySQL存在payment表数据
<2>mybatis映射XML
<select id="getBySerial" resultMap="payMap">
select id,serial from payment where
serial like "%${serial}%"
</select>
<3>controller接口
service、dao层代码直接省略了,没有任何处理,直接会调用xml中的SQL
@RequestMapping("/payment/getBySerial")
public R<List<PaymentDTO>> getBySerial(PaymentDTO dto){
return R.ok(paymentService.getBySerial(dto));
}
<4>测试
测试正常请求:http://127.0.0.1:6061/payment/getBySerial?serial=O
此时执行的SQL语句为:
select id,serial from payment where
serial like "%O%"
测试SQL注入请求:http://127.0.0.1:6061/payment/getBySerial?serial=O" or 1=1 or "serial=O
此时执行的SQL语句为:
select id,serial from payment where
serial like "%O" or 1=1 or "serial=O%"
!!!or 1 = 1 :过滤条件直接失效,能获取到表中的所有数据!,如下:
<5>bind防止SQL注入修改
因此,上述写法我们不能使用#{}去防止SQL注入,在不使用SQL函数和java代码不拼接%的情况下,我们想预防SQL注入,可以使用bind标签+#{}去替换${}拼接方式,案例如下:
- 更改xml中的SQL,其他代码不动:
select id,serial from payment where
<bind name="serial" value="'%'+serial+'%'" />
serial like #{serial}
继续测试:
测试正常请求:http://127.0.0.1:6061/payment/getBySerial?serial=O
此时执行的SQL语句为:
请求结果:
测试SQL注入请求:http://127.0.0.1:6061/payment/getBySerial?serial=O" or 1=1 or "serial=O
此时执行的SQL语句为:
结果如下: