`

PrepareStatment 与 Statement 比较

阅读更多
JAVA的JDBC有多种方法可以对数据库进行查询,但使用比较多的还是conn.prepareStatement()和conn.createStatement()两种方式打开数据库游标进行查询,具体方法就不多说了,主要说说两种方式的区别。个人感觉在开发中还是应尽量使用prepareStatement方式进行数据库查询,原因有以下几点:

1:安全性

prepareStatement绑定参数方式 比createStatement直接写sql更加安全,因为前者可以防止sql注入攻击。

以下脚本显示了一个简单的 SQL 注入。此脚本通过串联硬编码字符串和用户输入的字符串而生成一个 SQL 查询:
var sql = "select * from OrdersTable where ShipCity = '" + ShipCity + "'";  //其中 ShipCity 是用户在表单里输入的值

用户将被提示输入一个市县名称。如果用户输入 Redmond,则查询将由与下面内容相似的脚本组成:
SELECT * FROM OrdersTable WHERE ShipCity = 'Redmond'

但是,假定用户输入以下内容:
Redmond'; drop table OrdersTable--

此时,脚本将组成以下查询:
SELECT * FROM OrdersTable WHERE ShipCity = 'Redmond';drop table OrdersTable--'

这时假设使用createStatement方式查询你的程序可能像下面这样:
String querySql = “SELECT * FROM OrdersTable WHERE ShipCity = 'Redmond';drop table OrdersTable--'”;
stmt = conn.createStatement();
stmt.execute(querySql);

分号 (;) 表示一个查询的结束和另一个查询的开始。双连字符 (--) 指示当前行余下的部分是一个注释,应该忽略。如果修改后的代码语法正确,则服务器将执行该代码。SQL Server 处理该语句时,SQL Server 将首先选择 OrdersTable 中的所有记录(其中 ShipCity 为 Redmond)。然后,SQL Server 将删除 OrdersTable。

而使用prepareStatement 利用? 传参方式,java会自动将参数中的特殊字符进行转义,从而避免了以上的SQL攻击问题。

2:高效性

prepareStatement绑定参数方式 比createStatement更加高效。假设使用createStatement方式查询程序可能像下面这样:
String querySql = “SELECT * FROM CUSTOMERINFO WHERE NAME = ‘” + 姓名输入框的值 + “’”;
stmt = conn.createStatement();
stmt.execute(querySql);

如果用户第一次输入AAA查询SQL为:
SELECT * FROM CUSTOMERINFO WHERE NAME = ‘AAA’

如果此语句是第一次运行则Oracle发现这句SQL未在SHAREPOOL(共享池)中就会对这句SQL进行硬解析。而第二次用户输入BBB则查询SQL为:
SELECT * FROM CUSTOMERINFO WHERE NAME = ‘BBB’

如果此语句也是第一次运行, Oracle会从SHAREPOOL中查找此这句SQL以期望重用解析方案但发现没有找到,则会对上面这句SQL进行硬解析,因为Oracle会把
SELECT * FROM CUSTOMERINFO WHERE NAME = ‘AAA’
SELECT * FROM CUSTOMERINFO WHERE NAME = ‘BBB’

看成两句完全不同的SQL尽管两句只差了一个查询条件, 要知道Oracle的硬解析是很耗费资源的,它包括: 分析、限定(名称解析)、安全检查、优化等等。

而使用prepareStatement 利用? 传参方式就会利用Oracle绑定参数特性,解析时会忽略绑定参数,即:
SELECT * FROM CUSTOMERINFO WHERE NAME = ?

查询经过一次编译后,查询方案存储在Oracle的SHAREPOOL(共享池)中,可以用来检索和重用。在性能和伸缩性方面,这两者的差异是巨大的,甚至是惊人的。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics