zoukankan      html  css  js  c++  java
  • Statement与PreparedStatement的区别

    1、Statement为每一条Sql语句生成执行计划, 如果要执行两条sql语句 
    select colume from table where colume=1; 
    select colume from table where colume=2; 
    会生成两个执行计划,一千个查询就生成一千个执行计划。而生成计划是非常消耗资源的 
    2、PreparedStatement用于使用绑定变量重用执行计划 
    select * from xxx.sometable t where t.id=?; 
    通过set方法给sql语句按占位符"?"先后顺序赋值,只需要生成一个执行计划,可以重复使用。 
       当处理批量SQL语句时,这个时候就可以体现PrepareStatement的优势,由于采用Cache机制,则预先编译的语句,就会放在Cache中,下次执行相同SQL语句时,则可以直接从Cache中取出来,效率要比statement高好几倍 

    PreparedStatement类是Statement类的子类,它直接继承并重写了Statement的方法。PrepardStatement类有两大特点: 
      特点一:一个PreparedStatement的对象中包含的SQL声明是预编译的,因此当需要多次执行同一条SQL声明时,利用PreparedStatement传送这条SQL声明可以大大提高执行效率。 
      特点二:PreparedStatement的对象所包含的SQL声明中允许有一个或多个IN参数。创建类PreparedStatement的实例时,IN参数用“?”代替。在执行带参数的SQL声明前,必须对“?”进行赋值,为了对“?”赋值,PreparedStatement类中增添了大量的setXXX方法,完成对IN参数赋值。 
      ⑴创建PreparedStatement对象 
      与创建Statement类的实例方法类似,创建一个PreparedStatement类的对象也只需在建立连接后,调用Connection类中的方法 
      public abstract PreparedStatement prepareStatement(String sql) throws SQLException; 
      例 创建一个PreparedStatement的对象,其中包含一条带参数的SQL声明。 
      PreparedStatement pstmt=con.prepareStatement("INSERT INTO testTable(id,name) VALUES(?,?)"); 
      ⑵IN参数的赋值 
      PreparedStatement中提供了大量的setXXX方法对IN参数进行赋值。根据IN参数的SQL类型应选用合适的setXXX方法。 
      例 对上例,若需将第一个参数设为3,第二个参数设为XU,即插入的记录id=3,name="XU",可用下面的语句实现: 
      pstmt.setInt(1,3); 
      pstmt.setString(2,"XU"); 
    除了setInt,setLong,setString,setBoolean,setShort,setByte等常见的方法外,PreparedStatement还提供了几种特殊的setXXX方法。 
      ①setNull(int ParameterIndex,int sqlType) 
      这个方法将参数值赋为Null。sqlType是在java.sql.Types中定义的SQL类型号。 
      例 语句 
      pstmt.setNull(1,java.sql.Types.INTEGER); 
    将第一个IN参数的值赋成Null。 
      ②setUnicodeStream(int Index,InputStream x,int length); 
       setBinaryStream(int Index,inputStream x,int length); 
       setAsciiStream(int Index,inputStream x,int length); 
      当参数的值很大时,可以将参数值放在一个输入流x中,再通过调用上述三种方法将其赋于特定的参数,参数length表示输入流中字符串长度。 


        每一种数据库都会尽最大努力对预编译语句提供最大的性能优化.因为预编译语句有可能被重复调用.所以语句在被DB的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中(相当于一个涵数)就会得到执行.这并不是说只有一个Connection中多次执行的预编译语句被缓存,而是对于整个DB中,只要预编译的语句语法和缓存中匹配.那么在任何时候就可以不需要再次编译而可以直接执行.而statement的语句中,即使是相同一操作,而由于每次操作的数据不同所以使整个语句相匹配的机会极小,几乎不太可能匹配.比如: 
    insert into tb_name (col1,col2) values ('11','22'); 
    insert into tb_name (col1,col2) values ('11','23'); 
        即使是相同操作但因为数据内容不一样,所以整个个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存.这样每执行一次都要对传入的语句编译一次. 

        当然并不是所以预编译语句都一定会被缓存,数据库本身会用一种策略,比如使用频度等因素来决定什么时候不再缓存已有的预编译结果.以保存有更多的空间存储新的预编译语句. 

    Code Fragment 1: 
    String updateString = "UPDATE COFFEES SET SALES = 75 " + "WHERE COF_NAME LIKE ′Colombian′"; 
    stmt.executeUpdate(updateString); 
    Code Fragment 2: 
    PreparedStatement updateSales = con.prepareStatement("UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? "); 
    updateSales.setInt(1, 75); 
    updateSales.setString(2, "Colombian"); 
    updateSales.executeUpdate(); 

    片断2和片断1的区别在于,后者使用了PreparedStatement对象,而前者是普通的Statement对象。PreparedStatement对象不仅包含了SQL语句,而且大多数情况下这个语句已经被预编译过,因而当其执行时,只需DBMS运行SQL语句,而不必先编译。当你需要执行Statement对象多次的时候,PreparedStatement对象将会大大降低运行时间,当然也加快了访问数据库的速度。 
        这种转换也给你带来很大的便利,不必重复SQL语句的句法,而只需更改其中变量的值,便可重新执行SQL语句。选择PreparedStatement对象与否,在于相同句法的SQL语句是否执行了多次,而且两次之间的差别仅仅是变量的不同。如果仅仅执行了一次的话,它应该和普通的对象毫无差异,体现不出它预编译的优越性。 

    ps. java中preparedstatement为什么可以防止sql注入

    其实是预编译功能,用preparedstatement就会把sql的结构给数据库预编译。

    SQL注入 攻 击 是利用是指利用 设计 上的漏洞,在目 标 服 务 器上运行 Sql语 句以及 进 行其他方式的 攻 击 ,
    动态 生成 Sql语 句 时 没有 对 用 户输 入的数据 进 行 验证 是 Sql注入 攻 击 得逞的主要原因。
    对 于 JDBC而言, SQL注入 攻 击 只 对 Statement有效, 对 PreparedStatement 是无效的, 这 是因 为 PreparedStatement 不允 许 在不同的插入 时间 改 变查询 的 逻辑结 构。
    如 验证 用 户 是否存在的 SQL语 句 为 :
    select count(*) from usertable where name='用 户 名 ' and pswd='密 码 '
    如果在 用 户 名字段 中 输 入 ' or '1'='1' or '1'='1
    或是在 密 码 字段 中 输 入 1' or '1'='1
    将 绕过验证 ,但 这种 手段只 对 只 对 Statement有效, 对 PreparedStatement 无效。
    PreparedStatement 相 对 Statement有以下 优 点:
    1.防注入攻击
    2.多次运行速度快
    3.防止数据库缓冲区溢出
    4.代 码 的可读性可维护性好

    ps2. CallableStatement使用较少, 这里不做分析

    Shinobu
  • 相关阅读:
    Expected onClick listener to be a function, instead got type object
    css中的字体
    React Native之Touchable四组件
    0.44版本ReactNative真机运行的坑
    React Native之AsyncStorage
    VedioCaptureHelper
    2015年杂记一
    三级设置页面管理测试demo
    windows目录create、isExsit、remove
    验证reg注册表的操作
  • 原文地址:https://www.cnblogs.com/zedosu/p/6512019.html
Copyright © 2011-2022 走看看