zoukankan      html  css  js  c++  java
  • [J2EE] 有关 PreparedStatement

      今天同事遇到一个问题,简言之,就是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都是同一个,说明确实是拿的缓存的....

    代码如下:

     1 import java.sql.Connection;
     2 import java.sql.DriverManager;
     3 import java.sql.PreparedStatement;
     4 import java.sql.SQLException;
     5 
     6 import oracle.jdbc.OracleConnection;
     7 
     8 
     9 public class Test
    10 {
    11      static Connection con = null;
    12     public static void main(String args[]) throws ClassNotFoundException, SQLException 
    13     {
    14         con = ((oracle.jdbc.OracleConnection)getConnection());
    15         PreparedStatement ps0 = getPS(con);
    16         ps0.close();
    17         PreparedStatement ps1 = getPS(con);
    18         ps1.close();
    19         System.out.println(ps0==ps1);//如果是true,说明cache发生了作用
    20         
    21         
    22         con.close();
    23         con = null;
    24         con = ((oracle.jdbc.OracleConnection)getConnection());
    25         PreparedStatement ps2 = getPS(con);
    26         ps2.close();
    27         con.close();
    28         System.out.println(ps1==ps2);//如果是false,说明connection关闭后,会重新缓存
    29     
    30     }
    31     
    32     //获取PS实例
    33     public static PreparedStatement getPS(Connection con)throws ClassNotFoundException, SQLException{
    34           
    35            String sql = "select * from cms_turbine t where t.mapping like ?";
    36            PreparedStatement ps1 = con.prepareStatement(sql);
    37            ps1.setString(1, "hello");
    38           return ps1;
    39     }
    40     
    41     //建立连接
    42     public static Connection getConnection(){
    43         if(con == null){
    44         try{
    45             Class.forName("oracle.jdbc.driver.OracleDriver");
    46             con = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1523:XXX",xx,xx);
    47 
    48 //下面两句是为了开启cache
    49             ((oracle.jdbc.OracleConnection)con).setImplicitCachingEnabled(true);
    50             ((oracle.jdbc.OracleConnection)con).setStatementCacheSize(10);
    51        }catch(Exception e){
    52            e.printStackTrace();
    53        }
    54         }
    55         return con;
    56     }
    57 }

    执行结果是: 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

  • 相关阅读:
    k8s前期部署准备
    树莓派安装Gitlab-runner
    GitLab CI/CD 报错
    测试
    LVS结合keepalive
    LVS实现负载均衡安装配置详解
    LVS实现负载均衡原理
    私有仓库 gitlab 部署笔记
    Docker 案例: 在容器中部署静态网站
    docker 容器的启动方式
  • 原文地址:https://www.cnblogs.com/simple-code/p/4608181.html
Copyright © 2011-2022 走看看