mybatis的模糊查询中的"%"#{username}"%"怎么理解?

  1. mybatis的模糊查询中的"%"#{username}"%"怎么理解?
  2. 其中"%"在mybatis中这种用法怎么理解?一般的用法不是单引号吗?和'%'的区别是什么呢?


回答:

{变量名}可以进⾏预编译、类型匹配等操作,#{变量名}会转化为jdbc的类型。

select * from tablename where id = #{id}
假设id的值为12,其中如果数据库字段id为字符型,那么#{id}表⽰的就是'12',如果id为整型,那么id就是12,并且MyBatis会将上⾯
SQL语句转化为jdbc的select * from tablename where id=?,把?参数设置为id的值。
"%"#{username}"%" 会编译为 "%" '?' "%" ,
'%'#{username}'%' 会编译为 '%' '?' '%' 语法错误

${变量名}不进⾏数据类型匹配,直接替换。
select * from tablename where id = ${id}
如果字段id为整型,sql语句就不会出错,但是如果字段id为字符型,那么sql语句应该写成select * from table where id = '${id}'。
所以 '%${username}%' 会在执行的时候替换为 '%username%' 不会对数据进行校验,直接替换,所以会出现sql注入的情况

已参与了 SegmentFault 思否社区 10 周年「问答」打卡 ,欢迎正在阅读的你也加入。


回答:

以下基于mybatis版本:3.5.5 mysql版本:8.0.21

这和mysql的引号语法有关,个人理解的转义规则:
1、斜杠(\)加上单或双引号,使得他们被视为转译符号;

\'   \" 

2、双引号内连续的两个双引号被视为转义符号;单引号内连续的两个单引号也被视为转义符号;

"abc""abc"  //中间的两个相邻的双引号被视作一个转译的双引号

3、经过个人测试,"字符串A"'字符串B' 或者 '字符串A'"字符串B" 会被视作字符串A和字符串B的拼接;

"abc"'abc'  //大致可看做'abcabc'

4、成对的双引号之间的单引号会视为被转译如"ab'c";成对的单引号中的双引号同理;
5、两个相邻用双引号包裹的字符串之间若有空格(如"abc" "abc"),也会被视作两个字符串拼接,中间的双引号不会转译;单引号同理。

接下来请先了解一下mysql的预编译语句mysql中prepare_MySQL PREPARE语句

以下为mybatis开启mysql预编译的情况,方法是在数据库连接url后加上useServerPrepStmts=true

以select * from tablename where username like "%"#{username}"%" 为例
"%"#{username}"%"会首先被转化为"%"?"%",之后会执行mysql的prepare语句

PREPARE stmt1 FROM 'select * from table_name WHERE username like "%"?"%"';

这是一个错误的mysql语句,无法通过mysql语法检查。此时mybatis会放弃使用mysql的预编译,转而直接替换?为传过来的值:

select * from table_name WHERE username like "%"'用户名'"%";

最后交给mysql服务器执行。根据转译规则3,该语句是可以返回正确结果的。

那么'%'#{username}'%' 为什么不行?
同样把#{username}替换为?并执行mysql的预编译,预编译语句如下

PREPARE stmt1 FROM 'select * from table_name WHERE username like '%'?'%'';

同样无法通过语法检查,mybatis再转换为如下语句传给mysql服务器

select * from table_name WHERE username like '%''用户名''%';

注意 '%''用户名''%'' 根据转译规则2,现在相当于对 '用户名' 进行模糊查询,也就无法返回正确的结果

参考:
MySQL 中的单引号、双引号、反引号

以上是 mybatis的模糊查询中的"%"#{username}"%"怎么理解? 的全部内容, 来源链接: utcz.com/p/944518.html

回到顶部