热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

mybatis07:sql标签中"#{}"和"${}"的作用和比较

#{}占位符作用传参大部分使用#{},在数据库底层使用的是:PreparedStatement预编译处理对象数据库底层被解析为?,用来传值,是安全的数据库访问,可以防止sql注入通

"#{}"占位符

作用



  • 传参大部分使用"#{}",在数据库底层使用的是:PreparedStatement预编译处理对象

  • 数据库底层被解析为"?",用来传值,是安全的数据库访问,可以防止sql注入

  • 通过在SqlMapConfig.xml添加日志输出配置,在后文测试输出的结果中可以验证










写法



  • "#{}"里参数的写法,要参考parameterType的类型

  • 如果parameterType的类型是简单类型(8种基本类型(封装) + String类型),则"#{}"里变量名称任意





  • 如果parameterType的类型是实体类的类型,则"#{}"里只能是类中成员变量的名称,而且区分大小写

//User实体类中的属性
public class User {
private Integer id;
private String userName;
private Date birthday;
private String sex;
private String address;
}



insert into
users(username, birthday, sex, address)
values(#{userName}, #{birthday}, #{sex}, #{address})


"${}"占位符

用于字符串的拼接和字符串的替换



字符串拼接


作用



  • 一般用于模糊查询,建议少用,因为存在sql注入风险


写法



  • "${}"中参数名称的写法,分两种情况,与"#{}"的两种情况相同,可参考之

  • 注意:对于parameterType的类型是简单类型时,"${}"里变量名称随便写,但是分版本

    • 如果是3.5.1及以下版本,只能写"value"




模糊查询示例



  • 未优化前,存在sql注入风险





  • 优化后,使用"#{}"接受传参,底层是preparedStatement预编译对象,可以防止sql注入




字符串替换("${}"的主要作用)


需求:在users表中,根据地址或者用户名模糊查询用户信息

sql语句:

select * from users where username like '%模糊查询条件%'

select * from users where address like '%模糊查询条件%'

存在的问题:两条sql语句的结构在本质上是相同的,写两条语句十分冗余,可以采用替换列名的方式进行优化



UsersMapper.java接口

package com.example.mapper;
import com.example.pojo.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 数据访问层的接口,定义对数据库完成的CRUD的操作
*/
public interface UsersMapper {

//根据用户名或者地址模糊查询
List getByNameOrAddress(
@Param("colName")
String colName,
@Param("userName")
String userName
);
}


  • 接口分析:当接口中的方法的参数有多个时,用注解标识参数,sql标签可通过注解中声明的参数名获取参数


UsersMapper.xml文件










  • sql标签分析

    • 当标签对应的接口中的方法有多个参数时,标签中的入参类型,即:parameterType,取消不写,通过方法中注解的参数名称获取参数

    • 用于替换时只可以使用"${}",应该放在like前。"#{}"用来传值,应该放在like后用来占位传值




测试代码

package com.example.mapper;
import com.example.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
public class TestUsersMapper {
//时间刷
SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");
//SqlSession对象
SqlSession sqlSession;
//mybatis动态代理对象
UsersMapper usersMapper;
//获取SqlSession
@Before
public void getSqlSession() throws IOException {
//读取核心配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//获取SqlSession
sqlSession = factory.openSession();
//获取mybatis动态代理对象
usersMapper = sqlSession.getMapper(UsersMapper.class);
}
//归还SqlSession
@After
public void closeSession(){
sqlSession.close();
}

@Test
public void testGetByNameOrAddress(){
List users = usersMapper.getByNameOrAddress("username", "小");
//List users = usersMapper.getByNameOrAddress("address", "市");
users.forEach(System.out::println);
}
}

测试输出


根据用户名模糊查询

Checking to see if class com.example.mapper.TestUsersMapper matches criteria [is assignable to Object]
Checking to see if class com.example.mapper.UsersMapper matches criteria [is assignable to Object]
Opening JDBC Connection
Created connection 1293462056.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d18aa28]

==> Preparing: select id, username, birthday, sex, address from users where username like concat('%', ?, '%')
==> Parameters: 小(String)

<== Columns: id, username, birthday, sex, address
<== Row: 2, 小王, 2001-07-12, 1, 芜湖市
<== Row: 3, 小张, 1999-02-22, 1, 长沙
<== Row: 29, 小昕, 2001-03-14, 女, 忻州
<== Total: 3
Users{id=2, userName='小王', birthday=Thu Jul 12 00:00:00 CST 2001, sex='1', address='芜湖市'}
Users{id=3, userName='小张', birthday=Mon Feb 22 00:00:00 CST 1999, sex='1', address='长沙'}
Users{id=29, userName='小昕', birthday=Wed Mar 14 00:00:00 CST 2001, sex='女', address='忻州'}
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d18aa28]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d18aa28]
Returned connection 1293462056 to pool.
Process finished with exit code 0

根据地址模糊查询

Checking to see if class com.example.mapper.TestUsersMapper matches criteria [is assignable to Object]
Checking to see if class com.example.mapper.UsersMapper matches criteria [is assignable to Object]
Opening JDBC Connection
Created connection 1293462056.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d18aa28]

==> Preparing: select id, username, birthday, sex, address from users where address like concat('%', ?, '%')
==> Parameters: 市(String)

<== Columns: id, username, birthday, sex, address
<== Row: 2, 小王, 2001-07-12, 1, 芜湖市
<== Row: 7, 学委, 2001-05-13, 2, 平顶山市
<== Total: 2
Users{id=2, userName='小王', birthday=Thu Jul 12 00:00:00 CST 2001, sex='1', address='芜湖市'}
Users{id=7, userName='学委', birthday=Sun May 13 00:00:00 CST 2001, sex='2', address='平顶山市'}
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d18aa28]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d18aa28]
Returned connection 1293462056 to pool.
Process finished with exit code 0

测试结果分析



  • sql标签在底层分别被解析为

==> Preparing: select id, username, birthday, sex, address from users where username like concat('%', ?, '%')
==> Parameters: 小(String)

==> Preparing: select id, username, birthday, sex, address from users where address like concat('%', ?, '%')
==> Parameters: 市(String)


  • 由上可知

    • 标签中的${colName}分别被替换成了传入的"username"和"address",起到了替换作用

    • "#{}"被解析成"?",#{userName}分别拿到值:小(String)和市(String),起到占位传值作用





推荐阅读
  • 深入理解 SQL 视图、存储过程与事务
    本文详细介绍了SQL中的视图、存储过程和事务的概念及应用。视图为用户提供了一种灵活的数据查询方式,存储过程则封装了复杂的SQL逻辑,而事务确保了数据库操作的完整性和一致性。 ... [详细]
  • 本文详细介绍了IBM DB2数据库在大型应用系统中的应用,强调其卓越的可扩展性和多环境支持能力。文章深入分析了DB2在数据利用性、完整性、安全性和恢复性方面的优势,并提供了优化建议以提升其在不同规模应用程序中的表现。 ... [详细]
  • 本文详细分析了JSP(JavaServer Pages)技术的主要优点和缺点,帮助开发者更好地理解其适用场景及潜在挑战。JSP作为一种服务器端技术,广泛应用于Web开发中。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • PHP 编程疑难解析与知识点汇总
    本文详细解答了 PHP 编程中的常见问题,并提供了丰富的代码示例和解决方案,帮助开发者更好地理解和应用 PHP 知识。 ... [详细]
  • 本文详细介绍了如何使用libpq库与PostgreSQL后端建立连接。通过探讨PQconnectdb()函数的工作原理及其在实际应用中的使用方法,帮助读者理解并掌握建立高效、稳定的数据库连接的关键步骤。 ... [详细]
  • Windows服务与数据库交互问题解析
    本文探讨了在Windows 10(64位)环境下开发的Windows服务,旨在定期向本地MS SQL Server (v.11)插入记录。尽管服务已成功安装并运行,但记录并未正确插入。我们将详细分析可能的原因及解决方案。 ... [详细]
  • SQL中UPDATE SET FROM语句的使用方法及应用场景
    本文详细介绍了SQL中UPDATE SET FROM语句的使用方法,通过具体示例展示了如何利用该语句高效地更新多表关联数据。适合数据库管理员和开发人员参考。 ... [详细]
  • 本文总结了2018年的关键成就,包括职业变动、购车、考取驾照等重要事件,并分享了读书、工作、家庭和朋友方面的感悟。同时,展望2019年,制定了健康、软实力提升和技术学习的具体目标。 ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 在计算机技术的学习道路上,51CTO学院以其专业性和专注度给我留下了深刻印象。从2012年接触计算机到2014年开始系统学习网络技术和安全领域,51CTO学院始终是我信赖的学习平台。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • PHP 5.2.5 安装与配置指南
    本文详细介绍了 PHP 5.2.5 的安装和配置步骤,帮助开发者解决常见的环境配置问题,特别是上传图片时遇到的错误。通过本教程,您可以顺利搭建并优化 PHP 运行环境。 ... [详细]
  • 数据管理权威指南:《DAMA-DMBOK2 数据管理知识体系》
    本书提供了全面的数据管理职能、术语和最佳实践方法的标准行业解释,构建了数据管理的总体框架,为数据管理的发展奠定了坚实的理论基础。适合各类数据管理专业人士和相关领域的从业人员。 ... [详细]
  • 构建基于BERT的中文NL2SQL模型:一个简明的基准
    本文探讨了将自然语言转换为SQL语句(NL2SQL)的任务,这是人工智能领域中一项非常实用的研究方向。文章介绍了笔者在公司举办的首届中文NL2SQL挑战赛中的实践,该比赛提供了金融和通用领域的表格数据,并标注了对应的自然语言与SQL语句对,旨在训练准确的NL2SQL模型。 ... [详细]
author-avatar
五月妖精23
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有