有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

语句和PreparedStatement之间的java差异

准备好的语句是语句的一个稍微更强大的版本,并且应该始终至少和语句一样快速和容易处理
准备好的语句可以参数化

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

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

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

现在我的问题是:

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


共 (6) 个答案

  1. # 1 楼答案

    1. 它们是预编译的(一次),因此重复执行动态SQL(参数更改时)的速度更快。

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

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

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

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

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

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

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

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

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

    9. 在java中,分别通过setClob/setNClob、setBlob、setBinaryStream、setCharacterStream/setascistream/setNCharacterStream方法接受clob、blob、OutputStreams和reader作为参数“feed”

    10. 在java中,允许通过setURL、setRowId、setQLXML和setNull方法为SQL数据链接、SQL ROWID、SQL XML和NULL设置特定于数据库的值

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

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

  2. # 3 楼答案

    没什么可补充的

    1-如果您想在循环中执行查询(超过1次),由于您提到的优化,prepared语句可以更快

    参数化查询是避免SQL注入的好方法。参数化查询仅在PreparedStatement中可用

  3. # 4 楼答案

    与报表相比,编制报表的一些好处是:

    1. PreparedStatement帮助我们防止SQL注入攻击,因为它会自动转义特殊字符
    2. PreparedStatement允许我们使用参数输入执行动态查询
    3. PreparedStatement提供了不同类型的setter方法来设置查询的输入参数
    4. PreparedStatement比Statement快。当我们重用PreparedStatement或使用它的批处理方法来执行多个查询时,它变得更加可见
    5. PreparedStatement帮助我们使用setter方法编写面向对象的代码,而对于语句,我们必须使用字符串连接来创建查询。若要设置多个参数,那个么使用字符串连接编写查询看起来非常难看并且容易出错

    http://www.journaldev.com/2489/jdbc-statement-vs-preparedstatement-sql-injection-example上阅读有关SQL注入问题的更多信息

  4. # 5 楼答案

    语句是静态的,而准备好的语句是动态的

    语句适用于DDL,准备语句适用于DML

    语句速度较慢,而准备好的语句速度较快

    more differences(存档)

  5. # 6 楼答案

    a^{}的优点:

    • SQL语句的预编译和DB端缓存导致总体执行速度加快,并且能够在batches中重用相同的SQL语句

    • 通过引号和其他特殊字符的内置转义自动防止SQL injectionattacks。请注意,这需要使用任何PreparedStatement{}方法来设置值

      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对象的设置,例如^{}^{}^{}^{}^{}^{})和^{}^{})。在大多数类型上,您不能像在简单的Statement中那样“仅仅”执行toString()。您甚至可以在循环中使用^{}对其进行重构,如下面的实用程序方法所示:

      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();