Mybatis中使用 #{} 和 ${} 向sql传参时的区别

Java基础

浏览数:23

2019-9-11

    今天在工作时,使用MyBatis中向sql传递两个参数时,一直显示SQL语法错误,仔细检查,才发现传入的参数被加上了引号,导致传入的参数(要传入的参数是表名)附近出现语法错误。

错误写法:

1  select pro_type, name, b.info from #{0} a inner join #{1} b on a.config_id = b.config_id;

这种写法在控制台报错:

select pro_type, name, b.info from ? a inner join ? b on a.config_id = b.config_id;
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ”dana.auto_kpi_cfg_info’ a inner join ‘kingnetio.meta_config_info’ b on a.config’ at line 1

我们发现通过占位符传进来的参数两个表名都被加上了引号,这就导致在执行SQL时,会报语法错误。

后来特地查阅相关资料,改成使用${}:

 1 select pro_type, name, b.info from ${param1} a inner join ${param2} b on a.config_id = b.config_id; 

控制台日志信息如下:

Preparing: select pro_type, name, b.info from dana.auto_kpi_cfg_info a inner join kingnetio.meta_config_info b on a.config_id = b.config_id; 

在传入的表名参数上没有添加引号了。

现在特此整理这两种用法的不同点:

    (1)首先一点就是,#{}传递参数时,会在传递的参数上加上引号,在传递属性比如   name=? 时,可以很方便的使用#{}。而${}则不会添加引号,传递的是什么就会直接放到SQL中去执行。

    (2)通过上面的日志信息我们可以看到,#{}传递的参数实际上是通过占位符去传入到已经预编译好的SQL中去的,所以此时的SQL已经完成编译,只需要传参数就完成执行了。而${}在日志中显示的是直接将参数拼接成完整的SQL去DBMS中编译执行的。所以#{}方式实际上比${}方式更加安全,不会引起SQL注入。但是在传入表名参数时,只能使用${},这时候,必须要在接受参数的时候加入逻辑判断,判断参数中是否存在SQL语句,以防引起注入。

作者:jy的blog