分享

PrepareStatment 与 Statement 比较

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

1:安全性 

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

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

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

但是,假定用户输入以下内容: 
Java代码  收藏代码
  1. Redmond'; drop table OrdersTable--  

此时,脚本将组成以下查询: 
Java代码  收藏代码
  1. SELECT * FROM OrdersTable WHERE ShipCity = 'Redmond';drop table OrdersTable--'  

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

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

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

2:高效性 

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

如果用户第一次输入AAA查询SQL为: 
Java代码  收藏代码
  1. SELECT * FROM CUSTOMERINFO WHERE NAME = ‘AAA’  

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

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

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

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

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

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多