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

相关推荐
恒云客1 小时前
python uv debug launch.json
数据库·python·json
愈努力俞幸运2 小时前
第5章数据库,实体关系图,ER图
数据库·oracle
锥栗3 小时前
【其他】基于Trae的大模型智能应用开发
android·java·数据库
qq_353737543 小时前
安全跳转页(用于网站内链,优化SEO)—炫酷特效黑客风格版
数据库·安全
yangyanping201083 小时前
微服务设计之带过期时间的积分系统
数据库
I'mAlex4 小时前
金仓数据库平替MongoDB实操解析:多模融合赋能企业文档数据管理国产化升级
数据库·mongodb·kingbasees·金仓数据库
Pocker_Spades_A4 小时前
MongoDB 远程连不上?用cpolar告别局域网束缚,跨网访问就这么简单
数据库·mongodb
鸽芷咕4 小时前
从底层到实战,金仓多模数据库 MongoDB 兼容的技术实力到底有多强?
数据库·mongodb·金仓数据库
王家视频教程图书馆4 小时前
开源api
数据库