今天同事遇到一个问题,简言之,就是PreparedStatement的预编译究竟是怎么发挥作用的...

嘿嘿,说来惭愧,我以前就只知道PreparedStatement比Statement要好,要防SQL注入,就要用PS。

But,它的预编译作用,我却没关注过。现在经过一番研究,我不敢说我已经“了解”了,但是总归是思路清晰了一些,

我把我理解的整理出来希望对大家也有所帮助,有不对的地方请大家指正。

  • 预编译

首先要说的就是“预编译”。我们知道数据库在执行SQL语句的时候,首先要解析这个SQL语句,有一个“执行计划”的概念(差不多就是指寻找执行这个sql语句的一个最优路径)。对于经常执行的sql,数据库会把执行计划给缓存起来,对应的key就是该条sql。那么当再次执行同样的sql的时候,数据库就不再解析了,直接根据key返回相应的执行计划。这就节省了很多时间。

  • PreparedStatement(后面简称PS)

当我们说到PS的时候,可能我们会关心几个问题:

  1. 预编译发生在什么时候
  2. PS何时被缓存起来的

回答第一个问题:

“在创建PreparedStatement 对象时就指定了SQL语句,该语句立即发送给DBMS进行编译”。

回答第二个问题:

是当我们执行PS的close()方法时~~~~

  •  TEST

我针对PS cache,做了一个测验,想法是针对同一个SQL,如果我每次取到的PS都是同一个,说明确实是拿的缓存的....

代码如下:

 import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException; import oracle.jdbc.OracleConnection; public class Test
{
static Connection con = null;
public static void main(String args[]) throws ClassNotFoundException, SQLException
{
con = ((oracle.jdbc.OracleConnection)getConnection());
PreparedStatement ps0 = getPS(con);
ps0.close();
PreparedStatement ps1 = getPS(con);
ps1.close();
System.out.println(ps0==ps1);//如果是true,说明cache发生了作用 con.close();
con = null;
con = ((oracle.jdbc.OracleConnection)getConnection());
PreparedStatement ps2 = getPS(con);
ps2.close();
con.close();
System.out.println(ps1==ps2);//如果是false,说明connection关闭后,会重新缓存 } //获取PS实例
public static PreparedStatement getPS(Connection con)throws ClassNotFoundException, SQLException{ String sql = "select * from cms_turbine t where t.mapping like ?";
PreparedStatement ps1 = con.prepareStatement(sql);
ps1.setString(1, "hello");
return ps1;
} //建立连接
public static Connection getConnection(){
if(con == null){
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
con = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1523:XXX",xx,xx); //下面两句是为了开启cache
((oracle.jdbc.OracleConnection)con).setImplicitCachingEnabled(true);
((oracle.jdbc.OracleConnection)con).setStatementCacheSize(10);
}catch(Exception e){
e.printStackTrace();
}
}
return con;
}
}

执行结果是: true

false

说明同一个connection中两次取到的PS是同一个实例,不同connection不共用PS。

Note:

如果想要reuse PS,那再用完一个之后一定要close,意味着释放资源。在上面的代码中,如果main方法改写如下:

  public static void main(String args[]) throws ClassNotFoundException, SQLException
{
con = ((oracle.jdbc.OracleConnection)getConnection());
PreparedStatement ps0 = getPS(con);
ps0.close();
PreparedStatement ps1 = getPS(con);
// ps1.close(); ps1不close,后面ps2拿到的还是ps0吗?
System.out.println(ps0==ps1); PreparedStatement ps2 = getPS(con);
ps2.close();
con.close();
System.out.println(ps0==ps2);
}

执行结果是:true (因为ps0 close了)

false(因为ps1没有close,所以ps2并没有能拿到缓存中的PS)

参考:

http://www.linuxidc.com/Linux/2011-07/38776.htm

http://docs.oracle.com/cd/E11882_01/java.112/e10589/stmtcach.htm#JJDBC28649

[J2EE] 有关 PreparedStatement的更多相关文章

  1. java.sql.preparedstatement和java.sql.statement的区别

    本文转自CSDN,然后整理了一遍.原文出处:CSDN JDBC(java database connectivity,java数据库连接)的api中的主要的四个类之一的java.sql.stateme ...

  2. PreparedStatement是如何大幅度提高性能的

    本文讲述了如何正确的使用prepared statements.为什么它可以让你的应用程序运行的更快,和同样的让数据库操作变的更快.  为什么Prepared Statements非常重要?如何正确的 ...

  3. J2EE学习路线

    第一部分:  JAVA语言基础知识.包括异常.IO流.多线程.集合类.数据库.(切记基础知识一定要时时刻刻巩固,注意,如果你是想以最快速度学习J2EE,关于Java中的Swing知识点,就只做了解)  ...

  4. j2EE经典面试题

    1. hibernate中离线查询去除重复项怎么加条件? dc.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); 2. http协议及端口,sm ...

  5. 回头探索JDBC及PreparedStatement防SQL注入原理

    概述 JDBC在我们学习J2EE的时候已经接触到了,但是仅是照搬步骤书写,其中的PreparedStatement防sql注入原理也是一知半解,然后就想回头查资料及敲测试代码探索一下.再有就是我们在项 ...

  6. BEA WebLogic平台下J2EE调优攻略--转载

    BEA WebLogic平台下J2EE调优攻略   2008-06-25 作者:周海根 出处:网络   前 言 随着近来J2EE软件广泛地应用于各行各业,系统调优也越来越引起软件开发者和应用服务器提供 ...

  7. J2EE 学习路线

    分享一个比较好的学习网站    http://edu.51cto.com/roadmap/view/id-86.html ================================J2EE=== ...

  8. JDBC及PreparedStatement防SQL注入

    概述 JDBC在我们学习J2EE的时候已经接触到了,但是仅是照搬步骤书写,其中的PreparedStatement防sql注入原理也是一知半解,然后就想回头查资料及敲测试代码探索一下.再有就是我们在项 ...

  9. [J2EE规范]JDBC简单例子 标签: 数据库j2eejdbcjava 2017-06-29 10:55 353人阅读 评论(12)

    JDBC是什么? JDBC是java数据库连接(Java Database Connectivity),它是用于java编程语言和数据库之间的数据库无关连接的标准Java API,就是说,JDBC是用 ...

随机推荐

  1. poj3468树状数组的区间更新,区间求和

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 47174   ...

  2. S2_OOP第三章

    第一章 多态 概念 多态是具有表现多种型生态的能力的特征,同一个实现接口,使用不同的实例而执行不同的操作 子类转换父类(向上转型) 用父类接受子类,向上转型 向上转型的规则: 讲一个父类的引用志向一个 ...

  3. JAVA编码互转(application/x-www-form-urlencoded)

    本质上来说,java.net.UrlEncoder适用于将 String 转换为 application/x-www-form-urlencoded MIME 格式的静态方法 时 ,使用 但!一般情况 ...

  4. Web的架构与html5基础知识

    图1:完整的Web应用构架 图2:html5的基本结构 head 可添加在头部标签元素有→→title meta style link base script noscript meta 几个重要属性 ...

  5. Ionic3学习笔记(五)动画之使用 animate.css

    本文为原创文章,转载请标明出处 目录 前言 animate.css 的使用 animate.scss 的使用 1. 前言 animate.css 是一款强大的.跨浏览器的预设CSS3动画库,内置了很多 ...

  6. 高德地图测两点距离android比较精确的

    /////参考资料:高德官方:[http://lbs.amap.com/api/android-location-sdk/guide/android-location/getlocation] 主要三 ...

  7. C# JAVA成员访问修饰符比较

    在面向对象的访问修饰符中常用的有public ,private ,protected C# 访问修饰符: private < protected internal < internal/p ...

  8. JavaScript设计模式--门面模式

    外部与一个子系统的通信必须通过一个系统的一个门面对象进行,这就是门面模式. 门面模式具备如下两个角色: 1. 门面角色 客户端可以调用这个角色方法,此角色中有子系统的应用(知晓相关的(一个或多个)子系 ...

  9. nginx URL重写

    html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figure,footer,h ...

  10. Scrapy架构及其组件之间的交互

    最近在学Python,同时也在学如何使用python抓取数据,于是就被我发现了这个非常受欢迎的Python抓取框架Scrapy,下面一起学习下Scrapy的架构,便于更好的使用这个工具. 一.概述 下 ...