MyBatis动态sql之${}和#{}区别

前言

​ 接触mybatis也是在今年步入社会之后,想想也半年多了,缺没时间去系统的学习,只知道大概,也是惭愧。

​ 不知道有多少刚毕业的同学和我一样,到现在还没仔仔细细去了解你每天都会见到使用到的框架呢?

​ 什么?你也不知道mybatis动态sql中${}和#{}的差异?其实我也是今天才知道的,我们一起来学习一下吧。

正文

不够刺激,再增加一点前戏

​ 在mybatis中,使用sql查询时,经常需要动态传递参数。大家往往会采用以下方式:

-- 以根据order_no 查询订单信息为例
-- ①
select * from order where order_no = #{orderNo} -- ② select * from order where order_no = '${orderNo}' 

咦,不对!!!如果orderNo=’2017111695468435844135’,要最后执行后的结果与下面的语句执行结果一样,到底是用①还是②呢?

select * from order where order_no = '2017111695468435844135'

好吧。。。其实两种方式得到的结果是相同的。

but 在某些情况下,我们只能使用二者其一!!!


主题开始了


动态sql 是mybatis优于其他ORM框架的一个重要原因之一。

mybatis 在对 sql 语句进行预编译之前,会对 sql 进行动态解析,解析为一个BoundSql 对象,也是在此处对动态 SQL 进行处理的,使得#{}和${}在此处产生了差异。

#{}解析为一个JDBC中prepared statement的参数标记符

即:

select * from order where order_no = #{orderNo}

被解析为:

select * from order where order_no = ?

也即是,#{}被解析为一个参数占位符?.

${}则仅仅是一个纯粹的字符串替换

即:

select * from order where order_no = '${orderNo}' 

被解析为:

select * from order where order_no = '2017111695468435844135' 

也就是说,使用${}在预编译之前已经不包含变量name了,而#{}的变量替换是在DBMS中。

注意安全哦

  1. 能使用#{}的地方就别用${}.

    reason:1.使用#{},相同的预编译sql可以重复利用,性能比${}高;

    ​ 2. ${}在预编译之前已经被变量替换了,会存在sql注入问题。

​ 例如:

select * from ${tableName} where order_no = #{orderNo}

如果从客户端传入的tableName = “order;delete order; – “,那么sql动态解析之后,预编译之前的sql将变为:

select * from order;delete order; -- where order_no = #{orderNo}

– 之后的语句被注释了,然后,sql完全大变了。。。interesting!!!**

  1. 表名作为变量时,必须使用${}.表名是字符串,使用 sql 占位符替换字符串时会带上单引号 '',这会导致 sql 语法错误.

再简单讲讲sql预编译

定义:

​ sql 预编译指的是数据库驱动在发送 sql 语句和参数给 DBMS 之前对 sql 语句进行编译,这样 DBMS 执行 sql 时,就不需要重新编译。

为什么需要预编译

JDBC 中使用对象 PreparedStatement 来抽象预编译语句,使用预编译

    1. 预编译阶段可以优化 sql 的执行。 
      预编译之后的 sql 多数情况下可以直接执行,DBMS 不需要再次编译,越复杂的sql,编译的复杂度将越大,预编译阶段可以合并多次操作为一个操作。
    2. 预编译语句对象可以重复利用。 
      把一个 sql 预编译后产生的 PreparedStatement 对象缓存下来,下次对于同一个sql,可以直接使用这个缓存的 PreparedState 对象。

猜你喜欢

转载自www.cnblogs.com/eer123/p/9114196.html
今日推荐