千家信息网

mybatis中${}和#{}取值的区别有哪些

发表于:2025-02-01 作者:千家信息网编辑
千家信息网最后更新 2025年02月01日,这篇文章将为大家详细讲解有关mybatis中${}和#{}取值的区别有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。在使用mybatis框架时,在sql语句中获
千家信息网最后更新 2025年02月01日mybatis中${}和#{}取值的区别有哪些

这篇文章将为大家详细讲解有关mybatis中${}和#{}取值的区别有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

在使用mybatis框架时,在sql语句中获取传入的参数有如下两种方式:

  • ${paramName}

  • #{paramName}

那如何理解这两种传参方式呢?如下带你走近背后的奥义。

先来回顾下原生Jdbc查询:

public static void main(String[] args) throws Exception {  // sql语句  String sql = "select id,name from customer limit 2";  // 1.加载驱动, 此处使用的mysql驱动包是8.0版本, 若为5.0+版本, 请修改以下类路径  Class.forName("com.mysql.cj.jdbc.Driver");  // 2.获取数据库连接  String url = "jdbc:mysql://localhost:3306/work?useSSL=false&useUnicode=true" +    "&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true" +    "&useLegacyDatetimeCode=false&serverTimezone=UTC";  Connection conn = DriverManager.getConnection(url,"root", "123456");  // 3、获得可以执行sql语句的对象  Statement st = conn.createStatement();  // 4、使用对象去执行SQL语句  ResultSet rs = st.executeQuery(sql);  // 5、处理sql语句返回的结果集  while(rs.next()){    // 获得一行数据    Integer id = rs.getInt("id");    String name = rs.getString("name");    System.out.println("sql查询: id = " + id + " , name = " + name);  }  // 6、释放资源  rs.close();  st.close();  conn.close();}

控制台打印:

sql查询: id = 1 , name = 李白
sql查询: id = 2 , name = 杜甫

了解Jdbc的人会知道,其中第3、4步两条语句也可以换成如下两条:

// 3.创建 PreparedStatement 对象去执行sqlPreparedStatement preparedStatement = conn.prepareStatement(sql);// 4.执行sql语句ResultSet rs = preparedStatement.executeQuery();

我们来比较下区别:

  • 创建 PreparedStatement 对象时就把sql语句传入,在执行语句时就不用传入sql了;而 Statement 则刚好相反

这就引出了预编译的概念:

  • 如果使用PreparedStatement 对象,那么在执行第3步时,你既然已经传入了sql,则相当于这条sql会被数据库编译(数据库对sql语句的编译也是相当复杂的),所以在第4步执行的时候就不用再传入sql了,因为数据库已经知道你要执行的sql了,你只需要传入参数即可;

  • 如果使用Statement对象,那容易理解,数据库就没有提前去解析你的sql,因为你创建对象时都没有传入;当执行sql时,数据库再编译与执行。

看到这里,可能也仅仅只记住了一个预先编译sql了,一个没有预先编译,并没有了解到对于实际开发中的区别,以下将会举例说明。

那是否PreparedStatement对象这种方式就一定比Statement对象方式好?

没有那么绝对的事,大家要理解:

PreparedStatement对象的好处是,sql已经提前编译好,剩下的工作就是传入参数即可,编译好的sql可以复用,传入不同的参数,则数据库就将相应的参数填入编译好的sql。而Statement对象就是每次都要传入sql,丢给数据库去编译再执行;但是创建PreparedStatement对象的开销是比Statement对象大的。

回归到日常开发中,以上的区别我们压根也不用在意,事实上,百分之九十的场景我们使用的是PreparedStatement对象的方式,可能平时没有感知到,因为这是框架已经封装了。再者,当系统出现性能问题时,也绝对不会是因为这两个对象的原因。

以上简单回顾了下Jdbc中PreparedStatement与Statement对象;

可以预料,mybatis中${} 与 #{} 这两种取值方式就是相当于对应着PreparedStatement和Statement对象的区别了。

  • #{} 传参,代表sql已经预编译好了,你传入的参数真的就仅仅是参数!

  • ${} 传参,随便你传,传完了之后我再统一编译

那具体在使用中有什么不同呢?理解如下两种场景:

1.看如下service和sql语句

@Overridepublic List> listUser() {  String param = " and name = '李白'";  return indexMapper.listUser(param);}

以上代码能正常查询吗?

### Error querying database. Cause: java.sql.SQLSyntaxErrorException: You have
an error in your SQL syntax; check the manual that corresponds to your MySQL
server version for the right syntax to use near '' and name = \'李白\''

不能!会报sql语句规则错误,之前说了,#{} 取值代表sql已经编译好了,你传入的仅仅是参数

对应上面示例:

sql是指:select * from customer where 1 = 1

参数是指:and name = '李白'

此时sql可以正确运行,但是带上传入的参数就不行了,要理解你传入的真的仅仅是参数,不要和前面的sql混了。

但是这明显不对,因为想表达的其实是这样:

sql是指:select * from customer where 1 = 1 and name = ?

参数是指:'李白'

此时把参数替换进占位符是可以正常运行整个语句的。

所以此时应该用 ${param},因为用${}就没有提前编译好哪些是属于sql。

此示例表明:当你传入的参数不仅仅是参数,其实是一小段sql,想和原sql拼接在一起时,那就得用${}传参,相当于拼接好了之后丢给

数据库去解析整个语句;

sql中的问号代表参数占位符,这也是PreparedStatement对象特点之一,会将你传入的参数一一替换进占位符

反之如下:

@Overridepublic List> listUser() {  String param = "李白";  return indexMapper.listUser(param);}

这种情况使用 #{} 就是对的了,因为传入的参数仅仅就是参数,替换进sql语句中即可。

2.对参数类型的影响

@Overridepublic List> listUser() {  String param = "李白";  return indexMapper.listUser(param);}

以上代码能执行成功吗?

按理说,传入的仅仅是参数,不管是否预编译都应该能执行,但是实际还是会报错。

这是执行时打印出的sql语句:

select * from customer where 1 = 1 and name = 李白

显然,问题就在于参数没有加单引号,name字段是字符串类型,传入的也是字符串,偏偏mybatis转换之后没有加单引号。

所以当传入字符串类型参数时,应该用 #{} 取值,此时会自动加上单引号。

再看下面这种语句:

@Overridepublic List> listUser() {  String param = "name";  return indexMapper.listUser(param);}

此时传入的参数是要排序的字段名称,之前说了,如果采用#{} 取值,则实际是会自动加上单引号的,但是order by后面的排序字段需要单引号吗?

不需要,所以这种情况只能使用 ${} 取值。

你可能会发现此处用 #{} 取值也不会报错,那是因为mysql支持这种写法,但是查询的结果并不对。

日常开发中,只要能理解上述两种情形,那么就能正确使用 ${} 和 #{},由于这两种方式取值原理的区别,也容易明白 #{} 这种方式是可以防止sql注入的。

关于"mybatis中${}和#{}取值的区别有哪些"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

参数 对象 语句 编译 数据 数据库 方式 李白 查询 就是 引号 不用 代表 字段 字符 字符串 实际 篇文章 类型 开发 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 电脑共享服务器管理员密码 服务器安全永久免费的吗 联想服务器配置管理ip地址 视频网络安全教程 大连捷瑞网络技术 项目团队完成了一个从旧数据库 关于网络安全隐患的资料 查询数据库查数据 杭州正规软件开发收费报价表 信息网络安全高级工程师 网络安全风险相关的案例分析 书商书目数据库都有哪些 软件开发商标注册属于什么类 芜湖市网络安全和信息化 阿里云服务器增加带宽 什么是数据库的关系 网络安全关键技术研究 我的世界服务器老卡住 数据库中怎么设置一个表的默认值 服务器系统怎么重置 栖霞区旅游app软件开发 我的世界神奇宝贝服务器琉璃 我国数据库技术发展研究 华为网络安全违规举报网址 101数据库基础教学 常见软件开发模型优缺点 理想网络技术有限公司招聘 网络技术春考技能考试内容 网络技术工程师年薪多少 服务器系统怎么重置
0