对账单和准备结单之间的区别

2022-08-31 05:40:42

预准备语句是语句的稍微强大一些的版本,应始终至少与声明一样快速和易于处理。
预准备语句可以参数化

大多数关系数据库通过四个步骤处理 JDBC / SQL 查询:

  1. 解析传入的 SQL 查询
  2. 编译 SQL 查询
  3. 规划/优化数据采集路径
  4. 执行优化的查询/获取并返回数据

对于发送到数据库的每个 SQL 查询,语句将始终执行上述四个步骤。预准备语句预执行上述执行过程中的步骤 (1) - (3)。因此,在创建预准备语句时,会立即执行一些预优化。其效果是减少执行时数据库引擎上的负载。

现在我的问题是这样的:

“使用预准备语句还有其他好处吗?”


答案 1

预准备语句的优点

  • SQL 语句的预编译和数据库端缓存可加快整体执行速度,并能够批量重用相同的 SQL 语句。

  • 通过内置引号和其他特殊字符转义来自动防止 SQL 注入攻击。请注意,这要求您使用任何方法来设置值PreparedStatementsetXxx()

    preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email, birthdate, photo) VALUES (?, ?, ?, ?)");
    preparedStatement.setString(1, person.getName());
    preparedStatement.setString(2, person.getEmail());
    preparedStatement.setTimestamp(3, new Timestamp(person.getBirthdate().getTime()));
    preparedStatement.setBinaryStream(4, person.getPhoto());
    preparedStatement.executeUpdate();
    

    因此,不要通过字符串连接来内联 SQL 字符串中的值。

    preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email) VALUES ('" + person.getName() + "', '" + person.getEmail() + "'");
    preparedStatement.executeUpdate();
    
  • 简化了 SQL 字符串中非标准 Java 对象的设置,例如日期时间时间戳大十进制InputStreamBlob) 和 ReaderClob)。在大多数这些类型上,你不能像在简单的.您甚至可以将其全部重构为在循环中使用ReadkStatement#setObject(),如下面的实用程序方法所示:toString()Statement

    public static void setValues(PreparedStatement preparedStatement, Object... values) throws SQLException {
        for (int i = 0; i < values.length; i++) {
            preparedStatement.setObject(i + 1, values[i]);
        }
    }
    

    其可按如下方式使用:

    preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email, birthdate, photo) VALUES (?, ?, ?, ?)");
    setValues(preparedStatement, person.getName(), person.getEmail(), new Timestamp(person.getBirthdate().getTime()), person.getPhoto());
    preparedStatement.executeUpdate();
    

答案 2
  1. 它们是预编译的(一次),因此对于动态SQL的重复执行(参数更改)来说更快

  2. 数据库语句缓存可提高数据库执行性能

    数据库存储以前执行的语句的执行计划的缓存。这允许数据库引擎重用以前执行的语句的计划。由于 PreparedStatement 使用参数,因此每次执行时它都显示为相同的 SQL,因此数据库可以重用以前的访问计划,从而减少处理。语句将参数“内联”到 SQL 字符串中,因此不会显示为与数据库相同的 SQL,从而阻止缓存使用。

  3. 二进制通信协议意味着更少的带宽和对数据库服务器的通信调用速度更快

    预准备语句通常通过非 SQL 二进制协议执行。这意味着数据包中的数据较少,因此与服务器的通信速度更快。根据经验,网络操作比磁盘操作慢一个数量级,磁盘操作比内存中 CPU 操作慢一个数量级。因此,通过网络发送的数据量的任何减少都会对整体性能产生良好的影响。

  4. 它们通过转义提供的所有参数值的文本来防止 SQL 注入。

  5. 它们在查询代码和参数值之间提供了更强的分离(与串联的SQL字符串相比),提高了可读性,并帮助代码维护人员快速理解查询的输入和输出。

  6. 在java中,可以调用getMetadata()和getParameterMetadata()分别反映结果集字段和参数字段。

  7. 在java中,通过setObject,setBoolean,setByte,setDate,setDouble,setDouble,setFloat,setInt,setLong,setShort,setTime,setTime,setTimestamp智能地接受java对象作为参数类型 - 它转换为数据库可以理解的JDBC类型格式(不仅仅是toString()格式)。

  8. 在java中,接受SQL ARRAYs,作为通过setArray方法的参数类型

  9. 在java中,分别通过setClob/setNClob,setBlob,setBinaryStream,setCharacterStream/setAsciiStream/setNCharacterStream方法接受CLOBs,BLOB,OutputStreams和Reader作为参数“feeds”

  10. 在java中,允许通过setURL,setRowId,setSQLXML和setNull方法为SQL DATALINK,SQL ROWID,SQL XML和NULL设置特定于DB的值

  11. 在 java 中,从 Statement 继承所有方法。它继承 addBatch 方法,并且还允许添加一组参数值,以通过 addBatch 方法匹配一组批处理的 SQL 命令。

  12. 在java中,一种特殊类型的ReadkStatement(子类CallableStatement)允许执行存储过程 - 支持高性能,封装,过程编程和SQL,数据库管理/维护/调整逻辑,以及使用专有的数据库逻辑和功能


推荐