`

连接池优化之启用PoolPreparedStatements

 
阅读更多

来源:http://blog.itpub.net/29254281/viewspace-1064007/

 

DBCP连接池可以缓存PreparedStatement,本质上就是缓存游标。
    一个SQL语句,无论是Insert,Update,Delete还是Select都是游标操作,只不过Select游标指向查询结果,而其余的指向修改的目标。

    除了连接可以缓存,游标也是可以缓存的,主要是避免游标的反复创建。虽然Oracle对完全相同的SQL可以共享执行计划,但是也需要去共享池查询这个SQL的信息(该SQL的Hash值是否在共享池内)。缓存游标,则进一步优化,避免了反复查询共享池的操作(个人臆测).
    首先,做一个实验,证明游标可以反复利用。
    

  1. --创建实验表
  2. create table t as select rownum r from dual connect by level<10;
  3. set serveroutput on
  4. declare
  5.     cursor cur is select * from t;
  6.     v_record t%rowtype;    
  7. begin
  8.     open cur;
  9.     fetch cur into v_record;
  10.     dbms_output.put_line(v_record.r);
  11.     fetch cur into v_record;
  12.     dbms_output.put_line(v_record.r);
  13.     close cur;
  14.     
  15.     open cur;
  16.     fetch cur into v_record;
  17.     dbms_output.put_line(v_record.r);
  18.     fetch cur into v_record;
  19.     dbms_output.put_line(v_record.r);
  20.     close cur;
  21.     
  22. end;
  23. /
   
    实验结果:
            1
            2
            1
            2

可以看到游标在关闭之后,可以重新打开。并且重新打开的游标,与前次打开的游标,在数据上没有任何关系。第一次读到2,重新打开之后,会从1开始,而不是从3开始。

这个代码如果在JAVA程序中,就是这个样子的。

  1.         Class.forName("oracle.jdbc.OracleDriver");
  2.         Connection conn = DriverManager.getConnection("jdbc:oracle:thin:127.0.0.1:1521:orcl", "edmond", "edmond");
  3.         PreparedStatement cmd = conn.prepareStatement("select * from t");
  4.         //第一次调用
  5.         ResultSet rs = cmd.executeQuery();
  6.         rs.next();
  7.         System.out.println(rs.getString(1));
  8.         rs.next();
  9.         System.out.println(rs.getString(1));
  10.         //第二次调用
  11.         rs = cmd.executeQuery();
  12.         rs.next();
  13.         System.out.println(rs.getString(1));
  14.         rs.next();
  15.         System.out.println(rs.getString(1));
  16.         cmd.close();
  17.         conn.close();

    值得注意的是,PreparedStatement就表示Oracle的游标,但是一旦PreparedStatement关闭,就无法重新打开。所以复用PreparedStatement只需要在关闭之前重新调用executeQuery方法即可。
   
    如果连接池启动PoolPreparedStatements,则可能在每一个Connection的代理对象中,包括下面的结构
    Map<STRING, List> poolPreparedStatements
    其中Key是SQL语句或者SQL语句的Hash值,代理的Connection会根据SQL返回一个可用的prepareStatement;如果没有,则会创建新的prepareStatement对象。而这个返回的prepareStatement对象,也同样是代理对象。
    因为在调用连接池返回的prepareStatement的close方法时,不会真正的close这个对象,因为这样就无法实现复用的效果。可能只是修改了这个对象的标志位,标明其可用。

    下面是DBCP连接池开启游标缓存的
代码。
    可以想见 ds.getConnection()返回的Connection和PreparedStatement应该都是代理对象。
  1.     private static void testDataSource() throws SQLException {
  2.         BasicDataSource ds = new BasicDataSource();
  3.         ds.setUrl("jdbc:oracle:thin:127.0.0.1:1521:orcl");
  4.         ds.setUsername("edmond");
  5.         ds.setPassword("edmond");
  6.         ds.setPoolPreparedStatements(true);
  7.         ds.setMaxOpenPreparedStatements(300);
  8.         Connection conn = ds.getConnection();
  9.         PreparedStatement cmd = conn.prepareStatement("select * from t");
  10.         ResultSet rs = cmd.executeQuery();
  11.         rs.next();
  12.         System.out.println(rs.getString(1));
  13.         rs.next();
  14.         System.out.println(rs.getString(1));
  15.         cmd.close();
  16.         conn.close();
  17.     }
    另外,Oracle游标对应的是PreparedStatement,而不是ResultSet。
    并且MaxOpenPreparedStatements的设置应该小于Oracle的Open_Cursor的数值。
    
  1. public static void main(String[] args) throws ClassNotFoundException, SQLException {
  2.         List<PreparedStatement> list = new ArrayList<PreparedStatement>();
  3.         Class.forName("oracle.jdbc.OracleDriver");
  4.         Connection conn = DriverManager.getConnection("jdbc:oracle:thin:127.0.0.1:1521:orcl", "edmond", "edmond");
  5.         for (int i = 0; i < 305; i++) {
  6.             PreparedStatement cmd = conn.prepareStatement("select * from t");
  7.             
  8.             ResultSet rs = cmd.executeQuery();
  9.             rs.next();
  10.             rs.close();
  11.             rs = null;
  12.             list.add(cmd);
  13.         }
  14.         conn.close();
  15.     }
    结果出现异常:
Exception in thread "main" java.sql.SQLException: ORA-00604: 递归 SQL 级别 1 出现错误
ORA-01000: 超出打开游标的最大数
ORA-00604: 递归 SQL 级别 1 出现错误
ORA-01000: 超出打开游标的最大数
ORA-01000: 超出打开游标的最大数

    可以看到,如果PreparedStatement没有关闭,则Oracle那端的游标就没有释放。
    最终这个连接的游标超过Oracle的open_cursor数值(默认300),就会报错。
    所以启用了PoolPreparedStatements,一定注意设置MaxOpenPreparedStatements小于Oracle Open_Cursor的数值。    

   

分享到:
评论

相关推荐

    jdbc连接池配置(优化连接速度)

    jdbc数据库连接池,方便连接数据库,优化数据库连接速度。

    连接池连接池连接池

    连接池连接池连接池连接池连接池

    连接池案例 连接池案例

    连接池案例

    okhttp中连接池实现

    代码中包含okhhtp中连接池的设计,包含连接对象的添加,连接对象何时被移除。

    数据库连接池技术详解

    对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接池技术。某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源。 在较为完备的数据库连接池实现中,可根据...

    基于XML 的自优化数据库连接池的设计与实现

    提出一种自优化数据库连接池的设计方式。它可根据应用规模动态地调整设置参数, 进而选取对应的 管理策略, 其中策略可以存储在连接池的配置文件中或作为知识库保存。在对连接资源进行有效管理的同时, 可以对...

    C# 数据库连接池 C# 数据库连接池

    C# 数据库连接池 C# 数据库连接池 C# 数据库连接池 C# 数据库连接池

    dbcp连接池优化

    dbcp连接池优化详解,主要是如何应对链接僵死的现象

    kafka生产者连接池

    封装抽取了一个kafka生产者的连接池,能很好的用池的方式对kafka生产者连接点进行有效的管理

    如何启用和禁用数据库连接池以及如何设置连接池最大值和最小值

    如何启用和禁用数据库连接池以及如何设置连接池最大值和最小值:设置...一、数据库连接字符串默认为启用连接池。 二、禁用连接池:Pooling=False 三、设置连接池最大值和最小值:Max Pool Size=200;Min Pool Size=1;

    连接池 连接池连接池 连接池

    连接池 连接池 java JSP连接池 连接池 java JSP连接池 连接池 java JSP连接池 连接池 java JSP

    连接池 连接池 连接池 连接池

    连接池 连接池 连接池 连接池

    druid.rar阿里巴巴开源数据库连接池

    Druid为监控而生的数据库连接池,它是阿里巴巴开源平台上的一个项目。Druid是Java语言中最好的数据库连接池,Druid能够提供强大的监控和扩展功能.它可以替换DBCP和C3P0连接池。Druid提供了一个高效、功能强大、可...

    Tomcat连接池配置.doc

    Tomcat连接池配置,包你学会tomcat连接池的使用

    Http连接池工具类

    传统的HttpURLConnection并不支持连接池,如果要实现连接池的机制,还需要自己来管理连接对象。对于网络请求这种底层相对复杂的操作,个人以为如果有可用的其他方案,也没有必要自己去管理连接对象。 除了...

    RabbitMQ连接池+SpringBoot实现

    RabbitMQ连接池+SpringBoot实现。通过连接池实现将高效的管理RabbitMQ的Connection,并与springboot进行整合,实现消息发送,获取队列列表等功能。基于此可以进行更多功能的扩充。

    R2数据库连接池高性能连接池v1.3

    v1.3改进了清理线程可能出现的减少连接池中链接而不计数的问题。 v1.2处理了oracle环境下由于服务器关闭休眠链接造成的连接池循环检测进程异常退出的情况,改为当循环周期大于服务器关闭休眠链接间隔时,后台打印...

    数据库连接池配置

    这个文档详细讲述了mysql数据库连接池的配置以及数据库连接池的工作原理。

    达梦7数据库连接池,jdbcDriver

    达梦7数据库连接池,jdbcDriver,达梦7数据库连接池,jdbcDriver,达梦7数据库连接池,jdbcDriver,达梦7数据库连接池,jdbcDriver,达梦7数据库连接池,jdbcDriver,达梦7数据库连接池,jdbcDriver,

    Tomcat6配置连接池

    Tomcat6配置连接池很全面的东东

Global site tag (gtag.js) - Google Analytics