陈述与预备陈述之间的区别
“准备好的声明”是声明的稍微更强大的版本,应至less像声明一样简单快捷。
准备好的陈述可能是参数化的
大多数关系数据库分四步处理JDBC / SQL查询:
- parsing传入的SQL查询
- 编译SQL查询
- 计划/优化数据采集path
- 执行优化的查询/获取并返回数据
对于发送到数据库的每个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();
-
例如
Date
,Time
,Timestamp
,BigDecimal
,InputStream
(Blob
)和Reader
(Clob
),可以简化非标准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();
-
它们是预编译的(一次),因此dynamicSQL的重复执行速度更快(参数更改)
-
数据库语句高速caching提高了数据库执行性能
数据库为先前执行的语句存储执行计划的caching。 这允许数据库引擎重复使用先前执行的语句的计划。 因为PreparedStatement使用参数,所以每次执行时都会显示为相同的SQL,数据库可以重用以前的访问计划,减less处理。 语句将参数“内联”到SQLstring中,因此不会像数据库一样显示为相同的SQL,从而防止caching使用。
-
二进制通信协议意味着更less的带宽和更快的通信调用数据库服务器
编写的语句通常通过非SQL二进制协议执行。 这意味着数据包中的数据较less,所以与服务器的通信速度更快。 根据经验,networking操作比磁盘操作快一个数量级,比内存CPU操作快一个数量级。 因此,通过networking发送的数据量的减less将对整体性能产生良好的影响。
-
它们通过为所提供的所有参数值转义文本来防止SQL注入。
-
它们在查询代码和参数值之间提供了更强的分离(与连接的SQLstring相比),提高了可读性,并帮助代码维护人员快速理解查询的input和输出。
-
在java中,可以调用getMetadata()和getParameterMetadata()分别反映结果集字段和参数字段
-
在java中,通过setObject,setBoolean,setByte,setDate,setDouble,setDouble,setFloat,setInt,setLong,setShort,setTime,setTimestamp智能地接受java对象作为参数types – 它转换成DBtypes的格式,不仅仅是toString ()格式)。
-
在java中,通过setArray方法接受SQL ARRAYs作为参数types
-
在java中,分别通过setClob / setNClob,setBlob,setBinaryStream,setCharacterStream / setAsciiStream / setNCharacterStream方法接受CLOB,BLOB,OutputStreams和Readers作为参数“feeds”
-
在Java中,允许通过setURL,setRowId,setSQLXML和setNull方法为SQL DATALINK,SQL ROWID,SQL XML和NULL设置特定于DB的值
-
在java中,inheritanceStatement的所有方法。 它inheritance了addBatch方法,并且还允许添加一组参数值,以通过addBatch方法匹配批处理的SQL命令集。
-
在java中,一个特殊types的PreparedStatement(CallableStatement子类)允许执行存储过程 – 支持高性能,封装,过程编程和SQL,DBpipe理/维护/调整逻辑,以及使用专有的DB逻辑和特性
PreparedStatement
在防止SQL注入攻击方面是一个非常好的防御(但并非万无一失)。 绑定参数值是防止“小鲍比表”进行不必要的访问的好方法。
PreparedStatement对Statement的一些好处是:
- PreparedStatement帮助我们防止SQL注入攻击,因为它会自动转义特殊字符。
- PreparedStatement允许我们使用参数input来执行dynamic查询。
- PreparedStatement提供了不同types的setter方法来设置查询的input参数。
- PreparedStatement比Statement快。 当我们重用PreparedStatement或者使用批处理方法执行多个查询时,它变得更加明显。
- PreparedStatement帮助我们用setter方法编写面向对象的代码,而使用Statement我们必须使用String Concatenation来创build查询。 如果要设置多个参数,那么使用string连接编写查询看起来非常难看且容易出错。
没什么可补充的,
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语句
-
有效的重复执行
-
它是预编译的,所以速度更快
不要混淆:只要记住
- 语句用于静态查询意味着DDL查询,即创build,删除,更改和prepareStatement使用dynamic查询,即DML查询。
- 在Statement中,查询不是预编译的,而在prepareStatement查询是预编译的,因为prepareStatement是省时的。
- prepareStatement在创build时需要参数,而Statement不需要参数。 例如,如果你想创build表和插入元素,然后::创build表(静态)通过使用语句和插入元素(dynamic)通过使用prepareStatement …