预编译SQL

devtools/2025/1/14 20:25:17/

预编译SQL

预编译SQL是指在数据库应用程序中,SQL语句在执行之前已经通过某种机制(如预编译器)进行了解析、优化和准备,使得实际执行时可以直接使用优化后的执行计划,而不需要每次都重新解析和编译。这么说可能有一些抽象,那么让我们结合具体的代码进行讲解。

我们先来看两个JDBC代码,这是第一个:

java">String sql = "select id, username, password, name, age from user where username = 'liubei' and password = '123456' "
statement.executeQuery(sql);

这个代码完成了一个DQL语句,可以从user表中查找usernameliubeipassword123456的用户。看起来这个SQL语句和代码都十分简单。因为这个代码中的SQL语句是一个静态SQL(参数硬编码,直接将查询的条件硬编码在了SQL语句中,可以直接使用Statement类发起查询。

我们来看第二个代码:

java">// 编写SQL语句
String sql = "select id, username, password, name, age from user where username = ? and password = ?";
// 使用PreparedStatement对象创建预编译SQL
PreparedStatement statement = connection.prepareStatement(sql);
// 预编译SQL的两个参数都是String类型的,所以说使用setString方法补全其参数
statement.setString(1, "liubei");
statement.setString(2, "123456");
// 调用executeQuery方法发起一条DQL语句,并将查询结果封装到ResultSet类中
ResultSet resultSet = statement.executeQuery();

这个代码和上一个代码查找的效果、实现的功能是一模一样的,但是明显要复杂更多。其主要原因是因为这个代码中的SQL语句是一个预编译SQL(参数动态传递,使用?作为占位符,然后使用setString方法,为占位符传递参数,最后使用PreparedStatement类进行查询。在查询时,会将这个预编译的SQL和给占位符传递的参数都传给数据库处理。这确实比静态SQL麻烦了不少,但是预编译SQL使用十分广泛,并且安全性、性能都比静态SQL更高

安全性:防止SQL注入

SQL注入:通过控制输入来修改事先定义好的SQL语句,从而达到执行代码对服务器进行攻击的方法。客户端经常需要提交一些表单给服务端,通过SQL注入,在表单中输入特殊的字符,就可以改变定义好的SQL的意思,从而攻击服务器

常见场景:登录

当用户登录时,需要在表单中输入用户名和密码,然后提交表单给服务端,服务端根据用户提交的用户名和密码在数据库中进行查询(其本质是一个查询数据库的操作),查看是否用户名和密码相匹配。这个SQL语句其实十分简单:

sql">select * from user where username = 'root' and password = '123456';

假如能够查询到用户信息,那么就说明用户名和密码都正确,那么就可以登录;反之,用户名和密码至少有一个是错误的,则登录失败。看似这个SQL是没有什么问题的,但是假如在表单中这么输入呢:

用户名:随便输入,比如我输入一串乱码:498asdasas48das689。

密码:密码的输入就有讲究了,需要输入一些攻击性的内容:' or '1'='1。

这样输入以后,我们将用户名和密码拼接到SQL中看看是什么内容:

sql">select * from user where username = '498asdasas48das689' and password = '' or '1'='1';

这么一看SQL语句的意思就完全改变了,无论用户名输入什么,都可以登录,因为'1'='1'永远为true,并且两个条件之间用or连接,这个查询条件就永远为true了,也就代表着用户表中的所有数据都是符合查询条件的,所以说就可以登录了。这就是静态SQL的劣势,十分容易被SQL注入,遭到攻击。然而当使用了预编译的SQL之后,就可以解决这个问题:

预编译SQL是通过参数绑定来解决SQL注入的问题的:

参数绑定

在执行预编译的SQL语句之前,需要为预编译SQL中的每个占位符(?)提供具体的参数值。这个过程被称为参数绑定。参数绑定的过程确保了参数值以正确的数据类型传递给数据库,并且与SQL语法完全隔离。这意味着即使参数包含恶意构造的内容(如单引号'或其他特殊字符),它们也不会被解释为SQL代码的一部分,而是作为纯粹的数据处理

高性能

SQL语句的执行流程

 如图所示,一条SQL语句从编写到执行是要经过语法检查优化编译三个步骤的,而这三个步骤执行之后,这一条SQL语句就会缓存在内存中,假如后面需要使用同样的SQL语句,就可以直接从缓存中“拿”即可,无需再次经过这三步,但是假如有这样三个静态SQL:

sql">delete from user where id = 1;
delete from user where id = 2;
delete from user where id = 3;

这三个SQL极其相似,只是查询的条件略有不同,但是就算这样,也必须经过三次编译,才可以执行(分别),无法重复使用,因为这是静态SQL,每次的缓存的SQL内容都是写死了的,只要条件稍微变动,就必须重新编译。

但是假如使用预编译SQL:

sql">delete from user where id = ?

然后分别传递参数1、2、3,这样只会在第一次使用SQL进行编译(参数是1),缓存中的内容是delete from user where id = ?,后面传递参数2、3......时,预编译的SQL都可以在缓存中找到,可以直接使用,无需编译,极大提高了SQL的性能


http://www.ppmy.cn/devtools/150502.html

相关文章

可视化重塑汽车展示平台新体验

汽车展示平台利用图扑可视化技术,实现全方位、互动式车型展示,提供沉浸式用户体验,助力消费者深入了解车辆特性,优化销售沟通效率,推动汽车行业的数字化创新。

uniapp中h5使用地图

export function loadTMap(key) {return new Promise(function(resolve, reject) {window.init function() {// resolve(qq) //注意这里resolve(TMap) //注意这里}var script document.createElement("script");script.type "text/javascript";// scrip…

【每日学点鸿蒙知识】调试、网络、缓存、富文本编辑等

1、如何使用发布证书进行调试? 由于部分功能需要校验证书信息,所以需要使用调试证书和发布证书分别进行调试,但是使用发布证书后出现安装错误05/14 19:04:39: Install Failed: error: failed to install bundle.code:9568322error: signatur…

unity打包sdk热更新笔记

基础打包需要知识: 安装包大小不要超过2G,AB包数量过多会影响加载和构建,多次IO,用Gradle打包,要支持64位系统,不同的渠道包:让做sdk的人支持,提供渠道包的打包工具 配置系统环境变量…

双线性插值算法:原理、实现、优化及在图像处理和多领域中的广泛应用与发展趋势(二)

五、图像金字塔和多尺度分析 双线性插值在图像金字塔的构建中也发挥着重要的作用。图像金字塔是一种多分辨率表示图像的结构,通常包括一个原始图像的不同分辨率的版本。在构建图像金字塔时,我们可以通过不断地对图像进行下采样(缩小&#xf…

TypeScript 爬虫项目实战:抓取豆瓣电影 Top 250(TypeScript简单应用)

项目介绍 通过 TypeScript 实现一个简单的爬虫程序,从豆瓣电影 Top 250 页面抓取电影的标题和评论信息,并将数据存储到本地 JSON 文件中。该项目使用了 superagent 和 cheerio 两个核心工具: superagent:一个轻量的 HTTP 请求库…

性能测试工具的原理与架构解析

🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 在软件开发与运维领域,性能测试是确保系统稳定、高效运行的关键环节。性能测试工具作为实现这一目标的重要工具,通过模拟真实用户行为和负载…

vue时间格式转换

在 Vue 前端中,如果你想将日期格式改为 "yyyy-MM-dd HH:mm:ss",可以使用 JavaScript 的 Date 对象以及常用的日期处理库(比如 moment.js 或 dayjs)来实现格式化。以下是两种常见的解决方案: 方法 1: 使用 d…