创建时:

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,; 等做费尽心机的判断和过虑 。

【Java】PreparedStatement VS Statement的更多相关文章

  1. 【Java】-NO.16.EBook.4.Java.1.012-【疯狂Java讲义第3版 李刚】- JDBC

    1.0.0 Summary Tittle:[Java]-NO.16.EBook.4.Java.1.012-[疯狂Java讲义第3版 李刚]-  JDBC Style:EBook Series:Java ...

  2. 【Java】-NO.20.Exam.1.Java.1.001- 【1z0-807】- OCEA

    1.0.0 Summary Tittle:[Java]-NO.20.Exam.1.Java.1.001-[1z0-807] Style:EBook Series:Java Since:2017-10- ...

  3. 【Java】-NO.12.Java.2.OCJP.1.001-【Java OCJP】-

    1.0.0 Summary Tittle:[Java]-NO.12.Java.2.OCJP.1.001-[Java OCJP]- Style:Java Series:OCJP Since:2017-0 ...

  4. 【Java】代处理?代理模式 - 静态代理,动态代理

    >不用代理 有时候,我希望在一些方法前后都打印一些日志,于是有了如下代码. 这是一个处理float类型加法的方法,我想在调用它前打印一下参数,调用后打印下计算结果.(至于为什么不直接用+号运算, ...

  5. 【Java】推断文件的后缀名

    这本来不是一个问题,利用框架本来有的方法.或者File类的getPath()方法,取出要推断文件路径.或者getName()方法取出文件路径,成为一个String字符串如果为fileName之后,再对 ...

  6. 【JAVA】【NIO】3、Java NIO Channel

    Java NIO和流量相似,但有些差异: ·通道可读写,流仅支持单向.读或写 ·异步通道读取 ·通道读写器,他们是和Buffer交替 道的实现 下面是Java NIO中最重要的通道的实现: ·File ...

  7. 【JAVA】【NIO】5、Java NIO Scatter / Gather

    标题手段Java NIO该分散体浓缩 Java NIO内置支持分散与收集.的概念主要用于信道分散聚集的读写. 读出的分散体的一个通道被读多个数据buffer在.因此.数据分散到多个buffer中. 对 ...

  8. 【Java】0X001.配置开发环境,JDK、classpath等

    [Java]0x01 配置开发环境,JDK.CLASSPATH等 一. 下载JDK安装文件 首先,进入Oracle官网Java页面. 注意,要下载的是JDK而不是JRE,这点很重要,因为JRE并不包含 ...

  9. for循环输出空心菱形的形状【java】

    使用for循环语句输出以下“空心菱形”效果: * * * * * * * * * * * * * * * * 建议优先参考笔者的另一篇文章:<for循环输出菱形的形状[java]> 代码: ...

随机推荐

  1. iOS之ProtocolBuffer搭建

    一.环境安装:pb编译器的安装 1.从https://github.com/google/protobuf/releases下载protocolBuffer对应版本编译器包,比如目前的对应的objc最 ...

  2. memcached全面剖析--5. memcached的应用和兼容程序

    我是Mixi的长野.memcached的连载终于要结束了.到上次为止,我们介绍了与memcached直接相关的话题,本次介绍一些mixi的案例和实际应用上的话题,并介绍一些与memcached兼容的程 ...

  3. 自动化部署必备技能—定制化RPM包

    回顾下安装软件的三种方式: 1.编译安装软件,优点是可以定制化安装目录.按需开启功能等,缺点是需要查找并实验出适合的编译参数,诸如MySQL之类的软件编译耗时过长. 2.yum安装软件,优点是全自动化 ...

  4. umdh windbg分析内存泄露

    A.利用工具umdh(user-mode dump heap)分析:此处以程序MemoryLeak.exe为例子 1.开启cmd 键入要定位内存泄露的程序gflags.exe /i memroylea ...

  5. Entity Framework中实体模型命名空间的问题

    在添加一个实体数据模型的时候(就是扩展名为edmx那位)属性里明明设置了自己的命名空间,但是后台的Designer.cs命名空间生成规则却是项目的默认命名空间加edmx文件所在文件夹的名称, 是BUG ...

  6. TOP字句加SQL变量的相关问题

    SQL Server数据库中的变量可以加载TOP字句之后,下文将对TOP字句加SQL变量的相关问题进行讨论,供您参考,希望对您学习SQL数据库有所帮助. SQL Server2005开始,TOP子句后 ...

  7. 如何快速学会android的四大基础----Service篇

    很多人都以为,只要学过一点java就可以马上写android应用了,这种想法的产生非常自然,因为现在网上有那么多的android开源实例,只要跟着来,也能够自己写一个播放器.但是,只有去写一个真正投入 ...

  8. 【转】IT业给世界带来的危机

    IT业给世界带来的危机 昨天写了文章之后,回忆起这几年在湾区的经历,觉得自己是一个很不幸的人.然而就在今天,我的自怜奇妙的转换成了另一种感情,因为我看到了更不幸的人…… 正在女朋友 Cinny 的父母 ...

  9. ThinkPHP 3.2 性能优化,实现高性能API开发

    需求分析 目前的业务全站使用ThinkPHP 3.2.3,前台.后台.Cli.Api等.目前的业务API访问量数千万,后端7台PHP 5.6,平均CPU使用率20%. 测试数据 真实业务 php5.6 ...

  10. virtualbox 最小化安装centos7 配置双网卡(nat和桥接)记录----已经过期

    该文章已经过期   请参考另一篇文章:virtualbox 安装centos7 配置桥接网卡,实现主机和虚拟机互通,虚拟机可以访问外网,解决无法上网问题   先说明一下为什么要配置双网卡? 配置nat ...