Mybatis中#{}和${}区别以及预编译理解

开发中经常使用mybatis的orm框架对数据库进行相关操作,mybatis最大的好处就是可以使用动态sql,即在mybatis对sql进行预编译之前会对sql语句进行动态解析,处理之后再进行预编译从而到达DBMS执行sql语句。而我们开发中经常用到的动态传参#{param}和${param}在动态解析时会有可能产生不同的sql语句,下面我们就来讨论一下如何正确使用#和$。

预编译

先来熟悉一下预编译,所谓预编译理解下来即:数据库驱动在发送sql和参数到DBMS(数据库管理软件,暂时这么理解吧)之前,先对sql语句进行编译处理,之后DBMS则可以直接对sql进行处理,不需要再次编译,提高了性能。这一点mybatis 默认情况下,将对所有的 sql 进行预编译处理。

使用预编译可以带来哪些好处?

JDBC中使用PreparedStatement来抽象预编译语句,从而使用达到预编译效果。
1:预编译阶段可以对sql语句进行优化。   
    预编译可以将多个操作步骤合并成一个步骤,一般而言,越复杂的sql,编译程度也会复杂,难度大,耗时,费性能,而预编译可以合并这些操作,预编译之后DBMS可以省去编译直接运行sql。
2:预编译语句可以重复利用。
    把一个 sql 预编译后产生的 PreparedStatement 对象缓存下来,下次对于同一个sql,可以直接使用这个缓存的 PreparedState 对象。有兴趣的可以查看mysql驱动包里面的ConnectionImpl类是如何操作预编译的,这里提一下缓存PreparedStatement,在执行预编译时会先去判断是否存在缓存,如果存在则对参数清空,绑定新的参数。如果不存在则调用数据库进行预编译处理生成一个PreparedStatement对象。

mybatis动态解析

关于动态解析的原理,可以参考这篇文章,写的非常详细mybatis动态解析原理
理解下来当我们在xml文件中写入动态sql之后,调用相关封装类进行解析处理,最终生成一个BounSql,该类包括sql语句,参数,参数源数据等参数。

#{}和${}在动态解析时的区别?

mybatis动态解析时,对于变量的值替换发生在不同阶段。
#{ } 解析为一个 JDBC 预编译语句(prepared statement)的参数标记符,变量替换完成在DBMS中。

${ } 仅仅为一个纯碎的 string 替换,在动态 SQL 解析阶段将会进行变量替换,DBMS拿到的即为执行的sql。

这里需要说明的是并不是使用${}一定会产生注入,或是一定会被显示替换变量。

例如当${}使用在字段的动态变量时,mybatis在动态解析时是会替换成一个string字符串的,不是显示的字段名字。select * from user where name = ${name};传入name为auth,则在动态解析时也会生成select * from user where name = 'auth';从而DBMS进行处理sql。这里${}和#{}可以达到相同的效果,区别就是#{}会生成一个预编译sql给DBMS,在DBMS完成变量的替换。
然而如果${}的位置发生在from后面或是order by(开发中经常会用到动态根据字段排序),这时候会显式的使用变量;select * from user where name='auth' order by ${column};select * from ${tableName} where name=#{name};这类的${}会进行显式处理,即传入什么直接替换,例如${column}=id和${column}='id'则会产生不同的效果。而此类语句有可能会产生sql的注入,经典的例子:select * from ${tableName} where name = #{name};传入变量tableName= "user;delete user;-- " 动态解析后的sql:select *fromuser;deleteuser;-- where name = ?;会存在注入。如果select * from #{tableName} where name = #{name};传入tableName="user" 则产生无法编译的sql错误。

结论:能使用#{}尽量使用,因为i#{}可以产生一个预编译对象,可以重复利用,不会产生sql注入,当语句必须使用表明或者字段名时,需要排除sql注入的可能,必须使用${}。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容