1.#{}和${}
1.参数是int型
${}:


#{}:


2.参数是String

#{}:

${}:

MySQL执行的语句:

复制到MySQL里查看哪里出错:


知:当参数为String时;
#{}自动加""
${}不加""
修改为:


如果是Integer类型,#{} 和 ${}都不用加引号
3.【预编译SQL】和【即时SQL】的区别
#{}:预编译SQL
【?】是占位符,先把SQL模板发给数据库,后面再传值,预编译,防止SQL注入。
比如:
select * from user_info where username = #{username}
MyBatis发给数据库的内容是:
select * from user_info where username = ?
过程:
先把这条带【?】的模板交给MySQL编译
------》再把传入的参数放入?
------》自动加上单引号
${}:即时SQL
字符串直接拼接,MyBatis先把内容拼到SQL里,拼成一条完整的SQL再发给数据库。
比如:
select * from user_info where username = ${username}
设参数为:zhangsan;
MyBtais在把这条SQL发给数据库之前,直接拼接字符串,变为:
select * from user_info where username = zhangsan
${}不会自动加单引号!如果想要正确执行,就要加''(在参数为String情况下)
预编译SQL优点:
缓存,#{}性能高、#{}防止SQL注入,更安全
即时SQL缺点:
有SQL注入的风险
2.SQL注入

场景:用户输入注入SQL
select * from user_info where username = '' or 1='1' --';
${}:
1='1':MySQL在比较的时候,会自动把'1'转为数字1,结果永远为true。
--:在MySQL里是注释符号,--后面整行的内容都会被数据库忽略,不再执行。在这里【--】把最后多余的【'】注释掉,避免语法报错。
SQL注入,打印结果并不是期望值。



#{}:
换成#{}传一模一样的参数,不会SQL注入。因为#{}是预编译占位符【?】,数据库先收到模板
select * from user_info where username=?
然后把【' or 1='1' --】这一整串当成一个【完整的普通字符串值】 放进【?】里,不回SQL注入。



3.实例演示
1.查询语句为#{}






2.将查询语句换为${}



即时SQL不一定会出现SQL注入,主要看代码怎么写。比如如果参数是Integer,${}不会产生SQL注入;而String会SQL注入。
4.${}的用法
虽然{}有SQL注入的风险,实际应用中要尽量减少{},但有些情况下必须使用${}写SQL:
1.按顺序查找



相当于这样写SQL:

改为:




同时${}仍可能会产生SQL注入问题,要进行参数校验
2.like查询




这个报错就是说:数据库jdbc准备给第一个占位符赋值,但是发现这条SQL里根本没有占位符。
因为MyBatis 规则:写在引号里面的 #{},不会被解析成预编译占位符? ,它就只是普通文字 #{like}
改为:



5.SQL拼接字符串实现like查询
因为使用${}会有SQL注入的风险,所以使用MySQL的CONCAT函数实现like查询




6.#{}和${}的异同
同:都是获取变量赋值的
异:
预编译SQL:
缓存,#{}性能高、#{}防止SQL注入,更安全。
即时SQL缺点:
有SQL注入的风险。
7.数据库
No-SQL:Redis,hbase等
关系型数据库:MySQL
如果用户量达到上亿级:
使用MySQL------分库分表
冷热时间
使用No-SQL:
8.寄语
