动态 sql 是 mybatis 的主要特性之一,在 mapper 中定义的参数传到 xml 中之后,在查询之前 mybatis 会对其进行动态解析。mybatis 为我们提供了两种支持动态 sql 的语法:#{} 以及 ${};两者都是动态的向sql语句中传入需要的参数。
#{}
1、解析
#{}可以实现预编译,在预编译过程中主要进行数据类型检查和安全检查两部分操作
数据类型检查表现在:#{} 将传入的参数(数据)在SQL中显示为字符串,会对自动传入的数据加一个双引号。
安全检查表现在:若变量的值带有引号,会对引号进行转义处理,这样可以防止sql注入
1.1、#{}表示一个占位符号 相当于 jdbc中的 ? 符号
#{}实现的是向prepareStatement中的预处理语句中设置参数值,sql语句中#{}表示一个占位符即?
1.2、#{}将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:select * from user where id= #{user_id},如果传入的值是11,那么解析成sql时的值为where id="11"
1.3、如果sql语句中只有一个参数,此时参数名称可以随意定义
如果sql语句有多个参数,此时参数名称应该是与当前表关联[实体类的属性名]或则[Map集合关键字],不能随便写,必须对应!(顺序上必须对应)
2、应用场景
需要在sql映射文件中动态拼接sql时,用#{}
${}
1、解析
1.1、${}将传入的值,直接显示在sql中
1.2、${value}中的value的值有限制,只能写对应的value值,不能随便写,因为${}不会自动进行jdbc类型转换
简单来说,jdbc不支持使用占位符的地方都可以使用${}
2、应用场景
2.1、可以用来传入sql片段,我们可以将数据表字段名、表名、数据库名等传入,来进行sql拼接
2.1、排序时使用order by 动态参数时,此时也只能使用${}
在模糊查询中如果使用${}进行字符串拼接,无法防止sql注入问题,如果使用concat函数进行拼接,则只针对mysql数据库有效;如果使用的是oracle数据库,则需要使用连接符号"||"。
这样显然比较麻烦,且不利于项目的移植。为此mybatis提供了<bind>元素来解决这一问题,我们完全没必要使用数据库语言,只要使用mybatis语言即可与所需参数连接。
<bind name = "pattern_username" value=" '%' +_parameter.getUsername() + '%'" />
select * from t_customer where username like #{pattern_username}
#{}和${}的相同点和不同点
1、相同点:
都能取到变量的值
2、不同点:
2.1、#可以实现预编译,会先把#{变量}编译成?,在执行时再取值,可以防止sql注入
2.2、$是直接进行字符串替换
sql注入
SQL 注入就是在用户输入的字符串中加入 SQL 语句,如果在设计不良的程序中忽略了检查,那么这些注入进去的 SQL 语句就会被数据库服务器误认为是正常的 SQL 语句而运行,攻击者就可以执行计划外的命令或访问未被授权的数据
[其原理和避免方式详见](SQL注入是什么,如何避免SQL注入? (biancheng.net))