Statement和PreparedStatement之间的区别

Cod*_*e.. 213 java jdbc

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

大多数关系数据库分四步处理JDBC/SQL查询:

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

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

现在我的问题是 - "使用预备声明还有其他优势吗?"

Bal*_*usC 188

优点PreparedStatement:

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

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

    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();
    
    Run Code Online (Sandbox Code Playgroud)

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

    preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email) VALUES ('" + person.getName() + "', '" + person.getEmail() + "'");
    preparedStatement.executeUpdate();
    
    Run Code Online (Sandbox Code Playgroud)
  • 简化非标准的Java对象的设定在SQL字符串,例如Date,Time,Timestamp,BigDecimal,InputStream(Blob)和Reader(Clob).在大多数类型中,你不能toString()像在简单中那样"只"做一个Statement.您甚至可以将其全部重构为PreparedStatement#setObject()在循环内使用,如下面的实用方法所示:

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

    可以使用如下:

    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();
    
    Run Code Online (Sandbox Code Playgroud)

  • 描述性和解释性文本,以及参考和示例,是一个很好的答案.+1 (4认同)
  • 我不能肯定地说Java,但一般来说,准备好的声明不会**预先形成"内置逃避引号和其他特殊字符"; 相反,它执行*可执行SQL和数据*的分离,在将SQL转换为查询计划后,将参数作为单独的信息包发送到DBMS. (2认同)

Gle*_*est 47

  1. They are pre-compiled (once), so faster for repeated execution of dynamic SQL (where parameters change)

  2. Database statement caching boosts DB execution performance

    Databases store caches of execution plans for previously executed statements. This allows the database engine to reuse the plans for statements that have been executed previously. Because PreparedStatement uses parameters, each time it is executed it appears as the same SQL, the database can reuse the previous access plan, reducing processing. Statements "inline" the parameters into the SQL string and so do not appear as the same SQL to the DB, preventing cache usage.

  3. Binary communications protocol means less bandwidth and faster comms calls to DB server

    Prepared statements are normally executed through a non-SQL binary protocol. This means that there is less data in the packets, so communications to the server is faster. As a rule of thumb network operations are an order of magnitude faster than disk operations which are an order of magnitude faster than in-memory CPU oeprations. Hence, any reduction in amount of data sent over the network will have a good effect on overall performance.

  4. They protect against SQL injection, by escaping text for all the parameter values provided.

  5. They provide stronger separation between the query code and the parameter values (compared to concatenated SQL strings), boosting readability and helping code maintainers quickly understand inputs and outputs of the query.

  6. In java, can call getMetadata() and getParameterMetadata() to reflect on the result set fields and the parameter fields, respectively

  7. In java, intelligently accepts java objects as parameter types via setObject, setBoolean, setByte, setDate, setDouble, setDouble, setFloat, setInt, setLong, setShort, setTime, setTimestamp - it converts into JDBC type format that is comprehendible to DB (not just toString() format).

  8. In java, accepts SQL ARRAYs, as parameter type via setArray method

  9. In java, accepts CLOBs, BLOBs, OutputStreams and Readers as parameter "feeds" via setClob/setNClob, setBlob, setBinaryStream, setCharacterStream/setAsciiStream/setNCharacterStream methods, respectively

  10. In java, allows DB-specific values to be set for SQL DATALINK, SQL ROWID, SQL XML, and NULL via setURL, setRowId, setSQLXML ans setNull methods

  11. In java, inherits all methods from Statement. It inherits the addBatch method, and additionally allows a set of parameter values to be added to match the set of batched SQL commands via addBatch method.

  12. In java, a special type of PreparedStatement (the subclass CallableStatement) allows stored procedures to be executed - supporting high performance, encapsulation, procedural programming and SQL, DB administration/maintenance/tweaking of logic, and use of proprietary DB logic & features

  • “奇迹”是通过标准工厂方法实现的,这些方法返回接口的(特定于供应商的)实现:`Connection.createStatement` 和 `Connection.prepareStatement`。这种设计迫使您针对接口工作,因此您无需知道具体的实现类,并避免与此类实现类不必要的紧耦合。所有这些都在 Java jdbc 文档和 Java 文档中用示例进行了解释。:) (2认同)

duf*_*ymo 37

PreparedStatement防止SQL注入攻击是一种非常好的防御(但不是万无一失).绑定参数值是防止"小Bobby表"进行不必要访问的好方法.

  • 那么如何通过准备好的语句执行SQL注入呢? (6认同)
  • 您能举例说明SQL注入攻击如何对准备好的语句起作用吗?你在假设数据库代码中有错误吗? (3认同)
  • Michael,Variables作为参数传递给预准备语句将自动被JDBC驱动程序转义. (2认同)
  • 是的,但它远远超出"相当愚蠢".这令人愚蠢.没有一个知识的人会这样做. (2认同)
  • 此外,许多数据库供应商不支持在某些地方参数化列名(想想`ORDER BY`)和/或数值常量(想想`LIMIT`,`OFFSET`和其他分页解决方案),所以这些可以被SQL注入攻击即使在尽可能使用准备语句和参数化时也是如此. (2认同)

Pan*_*kaj 29

PreparedStatement对Statement的一些好处是:

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

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


mhs*_*ams 13

没什么可补充的,

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

2 - 参数化查询是避免SQL注入的好方法,只能在PreparedStatement中使用.


小智 10

声明是静态的,准备好的声明是动态的.

声明适用于DDL和DML的准备声明.

语句较慢而准备语句更快.

更多的差异


orb*_*ish 7

不能在Statement中做CLOB.

并且:( OraclePreparedStatement)ps


小智 6

Statement 将用于执行静态 SQL 语句,它不能接受输入参数。

PreparedStatement 将用于多次动态执行 SQL 语句。它将接受输入参数。


小智 5

准备好的语句会忽略sql注入,因此准备语句中的安全性会增加


Roo*_*oot 5

正如mattjames所引用

JDBC中对Statement的使用应100%本地化以用于DDL(ALTER,CREATE,GRANT等),因为这些是唯一不能接受BIND VARIABLES的语句类型。对其他所有类型的语句(DML,查询),都应使用PreparedStatements或CallableStatements。因为这些是接受绑定变量的语句类型。

这是事实,规则,法律-随时随地使用准备好的陈述。在几乎没有地方使用STATEMENTS。