转与 https://www.jianshu.com/p/bbeff97d41eb

动态sql是mybatis的主要特性之一。在mapper中定义的参数传到xml中之后,在查询之前mybatis会对其进行动态解析。

mybatis提供了两种支持动态sql的语法:#{} 、${}。

select * from t_user where username = '${username}';

select * from t_user where username = #{username};

username传参一致的话,这两种执行的结果是一样的,但是这两种方式在动态sql解析阶段的处理是不一样的。

1、#{}

解析为一个JDBC预编译语句(prepared statement)的参数标记符,把参数部分用占位符?代替。动态解析为:

select * from t_user where username = ? ;

而传入的参数将会经过PreparedStatement方法的强制类型检查和安全检查等处理,最后作为一个合法的字符串传入。

2、${}

这种方式只会做简单的字符串替换,在动态SQL解析阶段将会进行变量替换,假如传递的参数为Alice,最终处理结果如下:

select * from t_user where username = 'Alice' ;

这样在预编译之前的sql语句已经不包含变量了,因此可以看出${} 变量的替换阶段是在动态SQL解析阶段。

3、#{} ,${}两种方式对比

1)是否预防SQL注入

以上不同的处理方式可以看出,#{}预处理之后可以预防SQL注入;而${}在预编译之前就已经被替换,有被注入的风险,如下例:

如果传入的username 为 a' or '1=1,那么使用${}处理后直接替换字符串的sql就解析为:

select * from t_user where username = a' or '1=1' ;

这样的话所有的用户数据就被查出来了,这样就属于SQL注入。

如果使用#{},经过sql动态解析和预编译,会把单引号转义为\'那么sql最终解析为:

select * from t_user where username = "a\' or \'1=1 ";//这样会查不出任何数据,有效阻止sql注入

有的业务场景经常用到模糊查询,也就是like处理,推荐使用以下处理方式:

t_user.username like #username#

java代码里:

if (!StringUtil.isEmpty(this.username)) {

table.setUsername("%" + this.username + "%");

}

或者也可以使用数据库函数进行连接处理:

select  * from t_user u where username  like CONCAT('%', #username#, '%')

注意:以上就可以发现在某些特定场景下只能用${},比如order by 后的排序字段,表名、列名,因为需要替换为不变的常量。如果表名中使用#{}的话,会变成如下:

select * from #{tablename}-->tablename传参为t_user --->处理后变成 select * from 't_user',没有这样的表名,这样的话就会报错了,order by 同理。

2)性能考虑

因为预编译语句对象可以重复利用,把一个sql预编译后产生的PreparedStatement对象缓存下来,下次对于同一个sql,可以直接使用缓存的PreparedStatement对象,mybatis默认情况下,对所有的sql进行预编译,这样的话#{}的处理方式性能会相对高些。

总结:

能使用#{}的时候尽量使用#{}

表名、order by的排序字段作为变量时,使用${}。

转 - mybatis中${}、 #{}区别及应用场景的更多相关文章

  1. hibernate与mybatis的区别和应用场景

    mybatis 与 hibernate 的区别和应用场景(转) 1    Hibernate : 标准的ORM(对象关系映射) 框架: 不要用写sql, sql 自动语句生成: 使用Hibernate ...

  2. mybatis由浅入深day01_ 4.11总结(parameterType_resultType_#{}和${}_selectOne和selectList_mybatis和hibernate本质区别和应用场景)

     4.11 总结 4.11.1 parameterType 在映射文件中通过parameterType指定输入参数的类型.mybatis通过ognl从输入对象中获取参数值拼接在sql中. 4.11.2 ...

  3. list set map区别及适用场景

    list与Set.Map区别及适用场景   1.List,Set都是继承自Collection接口,Map则不是 2.List特点:元素有放入顺序,元素可重复 ,Set特点:元素无放入顺序,元素不可重 ...

  4. session,cookie,sessionStorage,localStorage的区别及应用场景

    session,cookie,sessionStorage,localStorage的区别及应用场景 浏览器的缓存机制提供了可以将用户数据存储在客户端上的方式,可以利用cookie,session等跟 ...

  5. Java内存的 静态方法和实例方法的区别及使用场景

    注意:变量指基本数据类型非对象,局部变量不能被静态修饰 1.(静态)成员变量存放在data segment区(数据区),字符串常量也存放在该区 2.非静态变量,new出来的对象存放在堆内存,所有局部变 ...

  6. 【转】ArrayList与LinkedList的区别和适用场景

    ArrayList 优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的). 缺点:因为地址连续,当要插入和删除时,Arra ...

  7. mybatis #与$区别

    mybatis #与$区别 #{}变量解析到SQL有带引号字符串:如查询条件变量如:select * from user where name = #{name}; 为:select * from u ...

  8. 转载>>C# Invoke和BeginInvoke区别和使用场景

    转载>>C# Invoke和BeginInvoke区别和使用场景 一.为什么Control类提供了Invoke和BeginInvoke机制? 关于这个问题的最主要的原因已经是dotnet程 ...

  9. java 常用集合list与Set、Map区别及适用场景总结

     转载请备注出自于:http://blog.csdn.net/qq_22118507/article/details/51576319                  list与Set.Map区别及 ...

  10. mybatis&Hibernate区别

    mybatis是一个不完全的orm框架,因为mybatis需要程序员自己写大量的sql,需要程序员对sql的掌握比较高,不过mybatis可以通过xml文件可以灵活的配置要运行的sql语句,将sql与 ...

随机推荐

  1. 零基础学Python--------入门篇 第1章 初始Python

    入门篇 第1章  初始Python 1.1  Pyhton 概述 1.1.1 了解 Python Python,本义是指“蟒蛇”.1989年,荷兰人Guido van Rossum发明了一种面向对象的 ...

  2. python多线程爬虫+批量下载斗图啦图片项目(关注、持续更新)

    python多线程爬虫项目() 爬取目标:斗图啦(起始url:http://www.doutula.com/photo/list/?page=1) 爬取内容:斗图啦全网图片 使用工具:requests ...

  3. USSD 杂记

    Android Oreo允许应用程序读取来自运营商的USSD消息. 利用emoney执行话费充值,需要执行USSD代码,尝试编写apk执行ussd代码进行充值. 尝试在Android8的系统上进行US ...

  4. float与double

    对数值类型的细节了解在大学里就是一带而过,自己始终也没好好看过.这是在csdn上看到的一篇文章,挺好的,记录下来. https://blog.csdn.net/Demon__Hunter/articl ...

  5. onScrollChanged()

    转载请标明出处:http://www.cnblogs.com/tangZH/p/8428100.html  onScrollChanged里面有四个参数 @Overrideprotected void ...

  6. Kasaraju算法--强连通图遍历及其python实现

    在理解有向图和强连通分量前必须理解与其对应的两个概念,连通图(无向图)和连通分量. 连通图的定义是:如果一个图中的任何一个节点可以到达其他节点,那么它就是连通的. 例如以下图形: 这是最简单的一个连通 ...

  7. 总结XSS与CSRF两种跨站攻击

    XSS:跨站脚本(Cross-site scripting),实际应是"CSS",但由于和层叠样式表CSS名称冲突,故改为"XSS" CSRF:跨站请求伪造(C ...

  8. 执行C#动态代码

    执行C#动态代码 using System; using System.Data; using System.Configuration; using System.Text; using Syste ...

  9. web渗透 学习计划(转载)

    作者:向生李链接:https://www.zhihu.com/question/21914899/answer/39344435来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...

  10. LeetCode算法题-License Key Formatting(Java实现)

    这是悦乐书的第241次更新,第254篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第108题(顺位题号是482).您将获得一个表示为字符串S的许可证密钥,该字符串仅包含字 ...