【Java】PreparedStatement VS Statement

创建时:  

    Statement statement = conn.createStatement();
    PreparedStatement preStatement = conn.prepareStatement(sql); 

执行时:    

    ResultSet rSet = statement.executeQuery(sql);
    ResultSet pSet = preStatement.executeQuery();

由上可以看出,PreparedStatement有预编译的过程,已经绑定sql,之后无论执行多少遍,都不会再去进行编译,

而 statement 不同,如果执行多变,则相应的就要编译多少遍sql,所以从这点看,preStatement 的效率会比 Statement要高一些。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;

public class JDBCTest {
    
    public static void main(String[] args) throws Exception {
        //1 加载数据库驱动
        Class.forName("com.mysql.jdbc.Driver");
        
        //2 获取数据库连接
        String url = "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8";
        String user = "root";
        String password = "root";
        Connection conn = DriverManager.getConnection(url, user, password);
        
        //3 创建一个Statement
        String sql = "select id,loginName,email from user where id=";
        String tempSql; 
        int count = 1000;
        long time = System.currentTimeMillis();
        for(int i=0 ;i<count ;i++){
            Statement statement = conn.createStatement();
            tempSql=sql+(int) (Math.random() * 100);
            ResultSet rSet = statement.executeQuery(tempSql);
            statement.close();
        }
        System.out.println("statement cost:" + (System.currentTimeMillis() - time));  
        
        String psql = "select id,loginName,email from user where id=?";
        time = System.currentTimeMillis();  
        for (int i = 0; i < count; i++) {  
            int id=(int) (Math.random() * 100);  
            PreparedStatement preStatement = conn.prepareStatement(psql);
            preStatement.setLong(1, new Long(id));  
            ResultSet pSet = preStatement.executeQuery();
            preStatement.close();  
        }  
        System.out.println("preStatement cost:" + (System.currentTimeMillis() - time));  
        conn.close();
    }
    
}

  上述代码反复执行,

statement cost:95           preStatement cost:90

statement cost:100         preStatement cost:89

statement cost:92           preStatement cost:86

当然,这个也会跟数据库的支持有关系,http://lucaslee.iteye.com/blog/49292  这篇帖子有说明

虽然没有更详细的测试 各种数据库, 但是就数据库发展 版本越高,数据库对 preStatement的支持会越来越好,

所以总体而言, 验证  preStatement 的效率 比 Statement 的效率高

2>安全性问题

这个就不多说了,preStatement是预编译的,所以可以有效的防止 SQL注入等问题

所以 preStatement 的安全性 比 Statement 高

3>代码的可读性 和 可维护性 
这点也不用多说了,你看老代码的时候  会深有体会

preStatement更胜一筹

 

1 、PreparedStatement 接口继承 Statement , PreparedStatement 实例包含已编译的 SQL 语句,所以其执行速度要快于 Statement对象。

2 、作为 Statement 的子类, PreparedStatement 继承了 Statement 的所有功能。三种方法

      execute 、 executeQuery 和 executeUpdate 已被更改以使之不再需要参数

3 、在 JDBC 应用中 , 如果你已经是稍有水平开发者 , 你就应该始终以 PreparedStatement 代替

      Statement. 也就是说 , 在任何时候都不要使用 Statement.

基于以下的原因 :

一 . 代码的可读性和可维护性 .

虽然用 PreparedStatement 来代替 Statement 会使代码多出几行 , 但这样的代码无论从可读性还是可维护性上来说 . 都比直接用Statement 的代码高很多档次 :

stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");//stmt 是 Statement 对象实例

 

perstmt = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)");

perstmt.setString(1,var1);

perstmt.setString(2,var2);

perstmt.setString(3,var3);

perstmt.setString(4,var4);

perstmt.executeUpdate(); //prestmt 是 PreparedStatement 对象实例

 

不用我多说 , 对于第一种方法 . 别说其他人去读你的代码 , 就是你自己过一段时间再去读 , 都会觉得伤心 。

 

PreparedStatement 尽最大可能提高性能 .

    语句在被 DB 的编译器编译后的执行代码被缓存下来 , 那么下次调用时只要是相同的预编译语句就不需要编译 , 只要将参数直接传入编译过的语句执行代码中 ( 相当于一个涵数 ) 就会得到执行 . 这并不是说只有一个 Connection 中多次执行的预编译语句被缓存 , 而是对于整个 DB 中 , 只要预编译的语句语法和缓存中匹配 . 那么在任何时候就可以不需要再次编译而可以直接执行 . 而 statement 的语句中 , 即使是相同一操作 , 而由于每次操作的数据不同所以使整个语句相匹配的机会极小 , 几乎不太可能匹配 . 比如 :

insert into tb_name (col1,col2) values ('11','22');

insert into tb_name (col1,col2) values ('11','23');

即使是相同操作但因为数据内容不一样 , 所以整个个语句本身不能匹配 , 没有缓存语句的意义 . 事实是没有数据库会对普通语句编译后的执行代码缓存 。

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

三 . 最重要的一点是极大地提高了安全性 。

即使到目前为止 , 仍有一些人连基本的恶义 SQL 语法都不知道 .

String sql = "select * from tb_name where name= '"+varname+"' and passwd='"+varpasswd+"'";

如果我们把 [' or '1' = '1] 作为 varpasswd 传入进来 . 用户名随意 , 看看会成为什么 ?

 

select * from tb_name = ' 随意 ' and passwd = '' or '1' = '1';

因为 '1'='1' 肯定成立 , 所以可以任何通过验证 . 更有甚者 :

把 [';drop table tb_name;] 作为 varpasswd 传入进来 , 则 :

select * from tb_name = ' 随意 ' and passwd = '';drop table tb_name; 有些数据库是不会让你成功的 , 但也有很多数据库就可以使这些语句得到执行 .

 

而如果你使用预编译语句 . 你传入的任何内容就不会和原来的语句发生任何匹配的关系 。

只要全使用预编译语句 , 你就用不着对传入的数据做任何过虑 。

而如果使用普通的 statement, 有可能要对 drop,; 等做费尽心机的判断和过虑 。

posted @ 2017-03-22 17:18  陈泽泽  阅读(502)  评论(0编辑  收藏  举报