JDBC PreparedStatement的作用机制

为什么说jdbc的PreparedStatement可以完全避免SQL注入的问题,还能高效利用数据库本身对查询的缓存?它的机制是什么,是数据库层面做的吗?


1 为什么能完全防范 SQL 注入?

JDBC Statement 中,SQL 语句是通过字符串拼接完成的。数据库拿到的是一串分不清哪里是"命令"、哪里是"数据"的字符。

  • 普通 Statement 的漏洞

    如果你拼接 SELECT * FROM users WHERE username = ' + admin' OR '1'='1 + ',数据库看到的指令是: "选出所有用户,只要 1 等于 1 就行" 。数据篡改了逻辑。

  • PreparedStatement :

    它采用了参数化查询(Parameterized Query)

    1. 预编译阶段 :驱动程序先向数据库发送一个带占位符的模版:SELECT * FROM users WHERE username = ?
    2. 数据绑定阶段 :再把具体的参数(如 admin' OR '1'='1)传过去。

关键点 :由于数据库已经提前完成了 SQL 的词法和语法分析,它已经认定这个 ? 位置只能是纯文本数据 。哪怕你传入的数据里包含 DROP TABLE 或者 OR 1=1,数据库也只会把它当成一个"名字特别奇怪的用户",而不会将其当作指令执行。


2 为什么能高效利用缓存?

这就涉及到数据库执行 SQL 的过程:解析(Parse) -> 优化(Optimize) -> 执行(Execute)

  • 硬解析(Hard Parse) :如果每次 SQL 字符串都不同(比如 ID 一直变),数据库就得针对每一条 SQL 重新计算执行计划(怎么查最快、用哪个索引),这非常耗 CPU。
  • 软解析(Soft Parse)PreparedStatement 允许数据库缓存执行计划

因为你发送的 SQL 模版始终是 SELECT * FROM items WHERE id = ?,数据库会发现:"诶,这个模版我见过,执行计划已经算好了,直接拿来用吧!"。

注意 :这种缓存主要发生在数据库的 SGA(系统全局区)/ Library Cache 中,而不是在 Java 程序里。


3 它的机制是什么?是数据库层面做的吗?

这是一个端到端(客户端 + 服务端) 的配合过程,其核心协议通常被称为 二进制协议(Binary Protocol)

3.1 宏观流程:

  1. 客户端(JDBC Driver) :将带有 ? 的 SQL 发给数据库,并请求一个 Statement ID

  2. 服务端(Database)

    • 校验 SQL 语法。
    • 生成执行计划。
    • 将该计划与 Statement ID 绑定并存入缓存。
    • 返回 ID 给客户端。
  3. 客户端 :调用 setInt()setString(),将纯数据(不含 SQL 关键字)和 Statement ID 打包发送。

  4. 服务端:根据 ID 找到缓存好的计划,直接把数据塞进去运行。

3.2 是不是所有数据库都支持?

  • 数据库支持:大多数现代关系型数据库(MySQL, PostgreSQL, Oracle, SQL Server)都在内核层面支持预编译。

  • 驱动模拟:如果某些老旧数据库不支持,JDBC 驱动会在本地进行"模拟(Client-side emulation)",即在本地安全地转义字符串再发过去。

    • 冷知识 :在 MySQL 中,默认情况下 JDBC 是在本地模拟预编译的。如果你想让它在数据库层面真正"硬核"执行,需要在连接字符串里加上 useServerPrepStmts=true

4 总结

PreparedStatement 的本质是把 SQL 变成了"带参数的函数"

  • 安全性:数据永远不会被误认为指令(类型安全)。
  • 性能:一次编译,多次运行(避免重复计算执行计划)。

稍微多说一句: 虽然它能防住 99% 的注入,但如果你在 SQL 模版里依然用字符串拼接表名(比如 SELECT * FROM ? 是不支持的,表名必须拼接),那还是会面临注入风险。这时候就需要你手动做严格的白名单校验了。

相关推荐
Javatutouhouduan18 小时前
2026Java面试的正确打开方式!
java·高并发·java面试·java面试题·后端开发·java编程·java八股文
JAVA面经实录91719 小时前
Java初级最终完整版学习路线图
java·spring·eclipse·maven
Cat_Rocky20 小时前
k8s-持久化存储,粗浅学习
java·学习·kubernetes
知识领航员20 小时前
蘑兔AI音乐深度实测:功能拆解、实测表现与适用场景
java·c语言·c++·人工智能·python·算法·github
释怀°Believe20 小时前
Spring解析
java·后端·spring
ooseabiscuit21 小时前
Laravel4.x:现代PHP框架的奠基之作
java·开发语言·php
节奏昂1 天前
【一份基础软件的下载地址和安装地址】
java
没什么本事1 天前
关于C# panel 添加lable问题 -- 明确X和Y 位置错误
android·java·c#
dhashdoia1 天前
GPT-5.5 代码开发实战:Codex与Browser Use深度集成与星链4SAPI优化方案
java·数据库·人工智能·gpt·架构
xuhaoyu_cpp_java1 天前
SpringMVC学习(二)
java·经验分享·笔记·学习·spring