你真的了解MyBatis中${}和#{}的区别吗?
动态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解析阶段将会进行变量替换,假如传递的参数为二师兄,最终处理结果如下:
select * from t_user where username = '二师兄' ;
这样在预编译之前的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#
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的排序字段作为变量时,使用${}。
来源:https://dwz.cn/tQwJGPbP
关注微信公众号【悟能之能】了解更多编程技巧。
回复"面经"获取面试资料
你真的了解MyBatis中${}和#{}的区别吗?的更多相关文章
- mybatis中#{}和${}的区别及order by的sql注入问题
		mybatis的#{}和${}的区别以及order by注入问题 原文 http://www.cnblogs.com/chyu/p/4389701.html 前言略,直奔主题.. #{}相当于j ... 
- MyBatis中#{ }和${ }的区别,数据库优化遵循层次和查询方法
		MyBatis中#{ }和${ }的区别详解 1.#将传入的数据当成一个字符串,会对自动传入的数据加一个 双引号. 例如order by #id#,如果传入的值是111,那么解析成sql时变为orde ... 
- mybatis中的#{}和${}区别
		mybatis中的#{}和${}区别 2017年05月19日 13:59:24 阅读数:16165 1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号.如:order by #use ... 
- Mybatis笔记八:MyBatis中#{}和${}的区别
		先给大家介绍下MyBatis中#{}和${}的区别,具体介绍如下: 1. $将传入的数据直接显示生成在sql中 2. #方式能够很大程度防止sql注入. 3.$方式无法防止Sql注入. 4.$方式一般 ... 
- Mybatis与Ibatis的区别
		Mybatis与Ibatis的区别: 1.Mybatis实现了接口绑定,使用更加方便 在ibatis2.x中我们需要在DAO的实现类中指定具体对应哪个xml映射文件, 而Mybatis实现了DAO接口 ... 
- mybatis与hibernate的区别持久层对比【面试题】
		Mybatis技术特点: 好处: 通过直接编写SQL语句,可以直接对SQL进行性能的优化: 学习门槛低,学习成本低.只要有SQL基础,就可以学习mybatis,而且很容易上手: 由于直接编写SQL语句 ... 
- JavaWeb_(Mybatis框架)JDBC操作数据库和Mybatis框架操作数据库区别_一
		系列博文: JavaWeb_(Mybatis框架)JDBC操作数据库和Mybatis框架操作数据库区别_一 传送门 JavaWeb_(Mybatis框架)使用Mybatis对表进行增.删.改.查操作_ ... 
- 【ORM】Mybatis与JPA的区别
		Mybatis与JPA的区别: 1.ORM映射不同: Mybatis是半自动的ORM框架,提供数据库与结果集的映射: JPA(Hibernate)是全自动的ORM框架,提供对象与数据库的映射: 2.可 ... 
- Mybatis与Hibernate的区别
		首先简单介绍下两者的概念: Hibernate :Hibernate 是当前最流行的ORM框架,对数据库结构提供了较为完整的封装. Mybatis:Mybatis同样也是非常流行的ORM框架,主要着力 ... 
随机推荐
- handlerMapping的初始化以及查找handler
			前提:HttpServletBean初始化了一些servlet配置,接着FrameWorkServlet创建了WebApplicationContext,最后DispatcherServlet初始化一 ... 
- webstorm和git安装后,terminal输入git命令,提示'git' 不是内部或外部命令
			最近换了工作,拿到电脑重新搭建编程环境,踩了好多git和sourcetree的坑,就是一直拉不下来代码,晕·~~经过几天的爬坑,终于可以拉取推送代码了!!! 问题:webstorm和git都安装完成, ... 
- Python-默背单词
			 数据库单词: 默认单词 单词说明 innodb 事务,主键,外键,tree,表行锁 myisam 主要以插入读取和插入操作 memory 所有数据保存在内存中 ACID 原子性,一致性,隔离性,持 ... 
- java的jar打包工具的使用
			java的jar打包工具的使用 java的jar是一个打包工具,用于将我们编译后的class文件打包起来,这里面主要是举一个例子用来说明这个工具的使用. 在C盘下的temp文件夹下面: ... 
- 15分钟让你了解如何实现并发中的Barrier
			说到Barrier,很多语言中已经是标准库中自带的概念,一般情况下,只需要直接使用就行了.而最近一些机缘巧合的机会,我需要在c++中使用这么个玩意儿.但是c++标准库里还没有这个概念,只有boost里 ... 
- Hadoop学习(8)-scala环境配置及简单使用
			学习scala的原因主要是因为以后要学习spark. scala是运行在java虚拟机上的,它是一种面向对象和函数式编程结合的语言,并兼容java程序 相对于java更简单 安装scala前提你要保证 ... 
- kafka同步异步消费和消息的偏移量(四)
			1. 消费者位置(consumer position) 因为kafka服务端不保存消息的状态,所以消费端需要自己去做很多事情.我们每次调用poll()方法他总是返回已经保存在生产者队列中还未被消费者消 ... 
- java并发编程(十八)----(线程池)java线程池框架Fork-Join
			还记得我们在初始介绍线程池的时候提到了Executor框架的体系,到现在为止我们只有一个没有介绍,与ThreadPoolExecutor一样继承与AbstractExecutorService的For ... 
- quick-cocos2dx在eclipse下的lua调试
			文中大部分内容来自http://cn.quick-x.com/?p=253,绿色标记部分为修改部分. 配置编译环境的基本步骤: 安装 Visual Studio 2012 安装 Java SDK 安装 ... 
- APP启动优化
			1. 去除启动黑屏 1.1 在style.xml中定义两种主题: <style name="AppTheme" parent="Theme.AppCompat.Da ... 
 
			
		