`

连接池优化之启用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的数值。    

   

分享到:
评论

相关推荐

    dbcp连接池优化

    ### DBCP连接池优化详解 #### 一、引言 在现代软件开发中,数据库连接池技术的应用极为广泛,特别是在高并发环境下,它可以显著提高应用程序处理能力并降低数据库资源的消耗。Apache DBCP(Database Connection ...

    Tomcat连接池的配置

    连接池的性能优化涉及多方面,包括合理设定最大连接数、最小连接数、超时时间,以及根据应用负载调整预编译语句的数量。此外,还可以考虑使用连接池监控工具,如JMX,监控连接池的状态,以便及时调整参数。 总结来...

    DBCP( Database Connection Pool )数据库连接池

    ### DBCP(Database Connection Pool)数据库连接池详解 #### 一、简介 DBCP(Database Connection Pool)是一个开源的数据库连接池实现,它依赖于Apache Jakarta commons-pool对象池机制。DBCP允许应用程序直接...

    jdbctemplate+druid连接池.docx

    JdbcTemplate 和 Druid 连接池是 ...Druid 提供的监控统计功能可以帮助开发者实时了解数据库连接池的状态,优化数据库性能。而 JdbcTemplate 则简化了 SQL 操作,降低了出错的可能性,提高了代码的可读性和可维护性。

    tomcat/resin使用全局数据库连接池资源

    总结,无论是Tomcat还是Resin,配置全局数据库连接池都是为了优化资源利用,提高系统效率。正确配置并理解连接池的参数对优化数据库性能至关重要。在实际项目中,应根据应用需求和服务器负载来调整这些参数,以达到...

    关于数据库连接池Druid使用说明

    总的来说,Druid连接池是现代Java应用中常用的数据库连接池实现之一,它提供了丰富的特性、高效的性能和灵活的配置选项,有助于提升应用的数据库操作性能和稳定性。在实际项目中,合理配置和使用Druid能帮助开发者更...

    JSP Spring中Druid连接池配置详解

    7. 开启PSCache:poolPreparedStatements属性设置为true时,Druid连接池可以开启PSCache功能,即连接上可以缓存PreparedStatements,以提高SQL执行效率。maxPoolPreparedStatementPerConnectionSize属性则用于限制每...

    DBCP配置详解

    DBCP通过一个预分配的连接池来优化管理数据库连接,提高访问数据库的性能。配置DBCP需要了解一些核心参数,这些参数可以帮助开发者根据不同的应用场景调整连接池的行为,从而获得最佳的性能和资源利用效率。 在配置...

    alibaba-druid

    - **解决方案**: 启用 `filters` 参数中的 `stat`、`wall` 等监控过滤器,通过 Web 控制台或日志查看详细的连接池监控信息。例如,可以通过 `stat` 过滤器查看 SQL 执行统计信息,通过 `wall` 过滤器识别潜在的 SQL...

    dbcp配置.doc

    DBCP(Database Connection Pool)是Apache的一个...通过这些配置,开发者可以根据应用的需求调整连接池的大小、连接的生命周期以及连接的验证策略,从而优化数据库性能,防止资源浪费,并确保应用的稳定性和可靠性。

    druid简单教程.docx

    总结来说,Druid 数据库连接池提供了一套完整的解决方案,包括性能优化、连接管理和监控。其简单易用的配置、强大的功能和优秀的性能,使得它在 Java 开发中占据一席之地。了解并熟练掌握 Druid 的使用,对于提高...

    Spring Boot使用和配置Druid

    Druid不仅提供了高效稳定的数据库连接管理,还提供了丰富的监控信息,便于我们了解数据库连接池的状态,及时发现和解决问题,从而优化应用性能。在实际开发中,可以根据项目需求调整各项参数,以达到最佳的性能表现...

Global site tag (gtag.js) - Google Analytics