陈述与预备陈述之间的区别

“准备好的声明”是声明的稍微更强大的版本,应至less像声明一样简单快捷。
准备好的陈述可能是参数化的

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

  1. parsing传入的SQL查询
  2. 编译SQL查询
  3. 计划/优化数据采集path
  4. 执行优化的查询/获取并返回数据

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

现在我的问题是 – “使用预备声明还有什么好处吗?

PreparedStatement优点:

  • SQL语句的预编译和DB端caching导致总体上更快的执行以及批量重用相同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(); 

    因此不要通过string-concatenating内联SQLstring中的值。

     preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email) VALUES ('" + person.getName() + "', '" + person.getEmail() + "'"); preparedStatement.executeUpdate(); 
  • 例如DateTimeTimestampBigDecimalInputStreamBlob )和ReaderClob ),可以简化非标准Java对象的设置。 在大多数types中,你不能像在一个简单的Statement那样“做” toString() 。 您甚至可以将其重构为在循环内部使用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]); } } 

    其中可以使用如下:

     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(); 
  1. 它们是预编译的(一次),因此dynamicSQL的重复执行速度更快(参数更改)

  2. 数据库语句高速caching提高了数据库执行性能

    数据库为先前执行的语句存储执行计划的caching。 这允许数据库引擎重复使用先前执行的语句的计划。 因为PreparedStatement使用参数,所以每次执行时都会显示为相同的SQL,数据库可以重用以前的访问计划,减less处理。 语句将参数“内联”到SQLstring中,因此不会像数据库一样显示为相同的SQL,从而防止caching使用。

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

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

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

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

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

  7. 在java中,通过setObject,setBoolean,setByte,setDate,setDouble,setDouble,setFloat,setInt,setLong,setShort,setTime,setTimestamp智能地接受java对象作为参数types – 它转换成DBtypes的格式,不仅仅是toString ()格式)。

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

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

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

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

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

PreparedStatement在防止SQL注入攻击方面是一个非常好的防御(但并非万无一失)。 绑定参数值是防止“小鲍比表”进行不必要的访问的好方法。

PreparedStatement对Statement的一些好处是:

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

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

没什么可补充的,

1 – 如果你想在一个循环中执行一个查询(超过1次),准备好的语句可以更快,因为你提到的优化。

2 – 参数化查询是避免SQL注入的一种好方法,只有在PreparedStatement中可用。

声明是静态的,准备的声明是dynamic的。

声明适用于DDL并为DML准备了声明。

语句较慢,而准备语句更快。

更多的差异

不能在声明中执行CLOB。

还有:( OraclePreparedStatement)ps

正如mattjames所引用的那样

在JDBC中使用Statement应该被100%本地化以用于DDL(ALTER,CREATE,GRANT等),因为这些是唯一不能接受BIND VARIABLES的语句types。 PreparedStatements或CallableStatements应该用于每个其他types的语句(DML,查询)。 因为这些是接受绑定variables的语句types。

这是一个事实,一个规则,一个法律使用准备无处不在的声明。 使用STATEMENTS几乎没有地方。

  • 阅读起来比较容易
  • 你可以很容易地使查询string是一个常量

准备好的语句会忽略sql注入,所以在准备好的语句中安全性会增加

语句将用于执行静态SQL语句,并且不能接受input参数。

PreparedStatement将被用于多次dynamic执行SQL语句。 它将接受input参数。

准备或参数化查询的另一个特点: 参考本文。

这个语句是数据库系统中同一个SQL语句高效重复执行的特性之一。 准备好的语句是一种模板,由具有不同参数的应用程序使用。

语句模板被准备并发送到数据库系统和数据库系统执行该模板上的parsing,编译和优化,并且不执行而存储。

有些参数如,where子句在模板创build后的应用程序中不传递,将这些参数发送到SQL语句的数据库系统和数据库系统使用模板,并按请求执行。

编写的语句对于SQL注入非常有用,因为应用程序可以使用不同的技术和协议来准备参数。

当数据数量增加,索引频繁更改时,Prepared Statements可能会失败,因为在这种情况下需要一个新的查询计划。

Statement接口执行不带参数的静态SQL语句

PreparedStatement接口(扩展语句)执行带/不带参数的预编译SQL语句

  1. 有效的重复执行

  2. 它是预编译的,所以速度更快

不要混淆:只要记住

  1. 语句用于静态查询意味着DDL查询,即创build,删除,更改和prepareStatement使用dynamic查询,即DML查询。
  2. 在Statement中,查询不是预编译的,而在prepareStatement查询是预编译的,因为prepareStatement是省时的。
  3. prepareStatement在创build时需要参数,而Statement不需要参数。 例如,如果你想创build表和插入元素,然后::创build表(静态)通过使用语句和插入元素(dynamic)通过使用prepareStatement …