PreparedStatement 和 Statement的区别

PreparedStatement 和 Statement的区别

      • [1. 代码可读性与可维护性](#1. 代码可读性与可维护性)
      • [2. 性能与预编译](#2. 性能与预编译)
      • [3. 安全性:防止 SQL 注入](#3. 安全性:防止 SQL 注入)
      • [4. 数据类型处理](#4. 数据类型处理)
      • [5. 适用范围](#5. 适用范围)
      • [6. 批量操作的支持](#6. 批量操作的支持)
      • 总结对比表

PreparedStatementStatement 都是 Java JDBC 中用来执行 SQL 语句的接口,但它们在性能、安全性、可读性 以及功能 上有着显著的区别。在实际开发中,通常推荐使用 PreparedStatement

以下是它们之间区别的详细展开说明:

1. 代码可读性与可维护性

  • Statement: 需要进行字符串拼接,尤其是当参数较多时,代码会变得冗长且难以阅读。

    java 复制代码
    // 需要手动拼接引号
    int id = 1;
    String name = "John";
    String sql = "SELECT * FROM users WHERE id = " + id + " AND name = '" + name + "'";
    Statement stmt = connection.createStatement();
    ResultSet rs = stmt.executeQuery(sql);
  • PreparedStatement: 使用占位符?,参数与 SQL 语句分离,结构清晰。

    java 复制代码
    String sql = "SELECT * FROM users WHERE id = ? AND name = ?";
    PreparedStatement pstmt = connection.prepareStatement(sql);
    pstmt.setInt(1, id);   // 参数索引从1开始
    pstmt.setString(2, name);
    ResultSet rs = pstmt.executeQuery(); // 这里不需要再传入sql

2. 性能与预编译

这是两者最核心的性能差异。

  • Statement: 每次执行 executeQuery()executeUpdate() 时,数据库系统都会对该 SQL 语句进行语法检查、语义检查、生成执行计划 。即使两次执行的 SQL 语句结构完全一样,只是参数不同(例如 WHERE id = 1WHERE id = 2),数据库也会把它们当作两个全新的语句来编译,不会重用之前的执行计划,导致效率较低。

  • PreparedStatement: 创建时会将 SQL 语句发送给数据库进行预编译。数据库一旦编译完成,就会将其缓存起来。之后无论传入什么参数,数据库都直接使用已编译好的执行计划,传入参数即可执行。

    • 优势: 在需要反复执行同一条 SQL 语句(如批量插入、频繁查询)时,可以节省每次编译的开销,显著提升性能。

3. 安全性:防止 SQL 注入

这是使用 PreparedStatement 最重要的理由。

  • Statement: 由于使用字符串拼接,攻击者可以利用输入数据修改原有的 SQL 逻辑。

    • 例子: 假设用户输入用户名作为参数,如果用户输入 ' OR '1'='1,拼接后的 SQL 可能变成:

      sql 复制代码
      SELECT * FROM users WHERE name = '' OR '1'='1' -- 恒成立,导致越权查询所有用户
  • PreparedStatement: 能够有效防止 SQL 注入。

    • 原因: PreparedStatement 在处理参数时,会对传入的参数进行转义 。它将传入的参数严格视为数据 ,而不是 SQL 关键字的一部分 。即使参数中包含 SQL 指令(如 OR 1=1),数据库也只会把它当作普通的字符串值来处理,而不会去执行其中的逻辑。

4. 数据类型处理

  • Statement: 所有参数都需要手动转换为字符串类型进行拼接,容易因格式问题引发错误,尤其是在处理日期、时间戳、二进制数据时。
  • PreparedStatement: 提供了丰富的 setXxx() 方法(如 setDate()setTimestamp()setBigDecimal()),能够更精确地将 Java 对象映射到对应的 SQL 数据类型,减少类型转换带来的错误。

5. 适用范围

  • Statement: 更适合执行不需要参数的 DDL(数据定义语言)语句 ,例如 CREATE TABLEALTER TABLE,或者执行一次性的、没有参数的 SQL。
  • PreparedStatement: 适用于需要传入参数的 DML(数据操作语言)语句SELECTINSERTUPDATEDELETE),尤其是需要批量执行的场景。

6. 批量操作的支持

  • PreparedStatement: 对于批量操作有很好的支持。可以使用 addBatch() 设置不同的参数,然后一次性通过 executeBatch() 提交给数据库执行,从而减少网络交互次数。

    java 复制代码
    // 预编译一次
    PreparedStatement pstmt = conn.prepareStatement("INSERT INTO users (id, name) VALUES (?, ?)");
    
    for (User user : userList) {
        pstmt.setInt(1, user.getId());
        pstmt.setString(2, user.getName());
        pstmt.addBatch(); // 添加到批次
    }
    
    pstmt.executeBatch(); // 一次性批量执行

总结对比表

特性 Statement PreparedStatement 结论
预编译 不预编译,每次执行都要编译 预编译,通常只编译一次 PreparedStatement 性能更好
SQL 注入 存在严重安全漏洞 自动防止 SQL 注入 PreparedStatement 更安全
可读性 参数拼接,混乱易错 参数占位符,结构清晰 PreparedStatement 更清晰
性能 低(尤其是循环执行时) 高(预编译+缓存执行计划) PreparedStatement 更高效
适用场景 表名/结构变化,DDL 数据操作,带参数的增删改查 各有所长,但 DML 多用后者

总的来说,在开发中,除非是执行结构变化的 DDL 语句,否则都应该优先使用 PreparedStatement

相关推荐
冉冰学姐5 小时前
基于ssm的技能比赛报名管理系统29817vn0(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
java·数据库·spring·ssm 框架应用
小小码农Come on7 小时前
Qt Creator + MSVC 2022 64bit 配置 Dump 文件生成与分析流程
数据库·qt
qiuyuyiyang8 小时前
【MySQL】环境变量配置
数据库·mysql·adb
jgyzl9 小时前
2026.3.11MyBatis-Plus基本使用与思考
java·数据库·mybatis
RDCJM9 小时前
【MySQL】在MySQL中STR_TO_DATE()以及其他用于日期和时间的转换
android·数据库·mysql
vanvivo9 小时前
redis 使用
数据库·redis·缓存
加成BUFF10 小时前
解决MySQL/MariaDB忘记root密码:完整重置教程(XAMPP/Windows版)
数据库·mysql·xampp
杰克尼10 小时前
苍穹外卖--day10
java·数据库·spring boot·mybatis·notepad++
dreamread10 小时前
完美解决phpstudy安装后mysql无法启动
数据库·mysql
小江的记录本10 小时前
【SQL】多表关系与冷热数据(全维度知识体系)
数据库·sql·mysql·数据库开发·数据库架构