前言:
同事开发遇到了一个问题,我好奇凑过去看了。
问题:
有个特别的需求,需要从 一条 SQL 中查出一个值 Name
SQL1 例如: Select Name From Where age =18 ,而这个值是个表名
取出这个 Name 传入到另一条 SQL 语句中,假设这个 Name = “table1”
SQL2 :Select * From dbo.table1 Where age =18 ,按照这样的设想,在 mybatis 中,写的语句如下
Select * From dbo.#{Name} Where age =18
结果报错了,控制台语句错误如下:
SQL: SELECT XXX FROM dbo.? WHERE XXX
Cause: java.sql.SQLException: sql injection violation, syntax error: error : pos 139, line 5, column 19, token QUES :
SELECT XXX FROM dbo.? WHERE age= ?;
uncategorized SQLException; SQL state [null]; error code [0];
解决:
我看了一下,怎么表名变成一个 ? 了,我怀疑是 #{} 的导致的,于是把它替换成 ${}
Select * From dbo.${Name} Where age = 18
分析
mybatis 在对 sql 语句进行预编译之前,会对 sql 进行动态解析,解析为一个 BoundSql 对象,也是在此处对动态 SQL 进行处理的。在动态 SQL 解析阶段, #{ } 和 ${ } 会有不同的表现
- ${ } 变量的替换阶段是在动态 SQL 解析阶段,而 #{ }变量的替换是在 DBMS 中
- #{ } 方式能够很大程度防止sql注入。
- ${ } 方式无法防止Sql注入。
- ${ } 方式一般用于传入数据库对象,例如传入表名.
所以,一般能用#的就别用$.