【问题标题】:OracleDataSource vs. Oracle UCP PoolDataSourceOracleDataSource 与 Oracle UCP PoolDataSource
【发布时间】:2010-11-28 12:17:27
【问题描述】:

我正在研究一些 JDBC Oracle 连接池项目,并遇到了一个新的(er)Oracle 池实现,称为通用连接池 (UCP)。现在,它使用一个新类 PoolDataSource 进行连接池,而不是 OracleDataSource [启用缓存选项]。我正在争论是否切换到这个新的实现,但找不到任何好的文档来说明这会给我带来什么(如果有的话)修复/升级。有谁有这两者的经验?优点/缺点?谢谢。

【问题讨论】:

    标签: oracle jdbc


    【解决方案1】:

    最新的 Oracle jdbc 驱动程序 (11.2.0.1.0) 明确指出 Oracle 隐式连接缓存(即使用 OracleDataSource 的缓存)已被弃用:

    Oracle JDBC 驱动程序发布 11.2.0.1.0 生产 Readme.txt

    此版本有什么新功能?

    通用连接池 在此版本中,Oracle 隐式连接缓存功能是 已弃用。强烈建议用户使用新的 Universal 而是连接池。 UCP 具有 ICC,还有更多。 UCP 在单独的 jar 文件中可用, ucp.jar。

    所以我认为最好开始使用 UCP,但它的文档并不是那么好。 例如,我没有找到将 UCP 与 spring 一起使用的方法...

    更新:我找到了正确的弹簧配置: 好的,我想我找到了正确的配置:

    <bean id="dataSource" class="oracle.ucp.jdbc.PoolDataSourceFactory" factory-method="getPoolDataSource">
        <property name="URL" value="jdbc:oracle:thin:@myserver:1521:mysid" />
        <property name="user" value="myuser" />
        <property name="password" value="mypassword" />
        <property name="connectionFactoryClassName" value="oracle.jdbc.pool.OracleDataSource" />
        <property name="connectionPoolName" value="ANAG_POOL" />
        <property name="minPoolSize" value="5" />
        <property name="maxPoolSize" value="10" />
        <property name="initialPoolSize" value="5" />
        <property name="inactiveConnectionTimeout" value="120" />
        <property name="validateConnectionOnBorrow" value="true" />
        <property name="maxStatements" value="10" />
    </bean>
    

    关键是要指定正确的工厂类和正确的工厂方法

    【讨论】:

    • 谢谢,我没看到。在 Spring 中使用它就像使用 OracleDataStore 一样,只是现在您设置特定的 bean 属性(如 AbandonConnectionTimeout),而不是传入缓存属性的 Map。
    • @user174630 我使用了这个配置,但我得到了java.lang.ClassNotFoundException: oracle.jdbc.pooling.Factory,尽管我在类路径中有 jars ucp.jar、commons-dbcp.jar 和 ojdbc6.jar
    • @AhmedWahbi 它叫oracle.ucp.jdbc.PoolDataSourceFactory
    【解决方案2】:

    PDS 是“通用的”,因为它为非 Oracle 数据库提供了与您在 ODS 中获得的相同级别的池功能,例如MySQL。

    UCP Dev Guidean article on Oracle websiteUCP Transition Guide

    我没有看到从 ODS 迁移到 UCP (PDS) 的任何直接好处,但未来 Oracle 可能会弃用 ODS 中的某些功能。我使用 ODS 有一段时间了,暂时对它很满意,但如果我刚开始,我会选择 PDS。

    【讨论】:

      【解决方案3】:

      我对 UCP 进行了广泛的评估,并决定不使用 UCP - please have a look at this post 了解详情。

      【讨论】:

        【解决方案4】:

        我测试了 UCP 并将其部署到 Spring 3.0.5 Hibernate 应用程序中,使用 Spring JMS 侦听器容器和使用 @Transactional 注释的 Spring 管理的会话和事务。由于单独的侦听器线程试图更新同一记录,数据有时会导致 SQL 约束错误。发生这种情况时,由@Transactional 注释的一个方法引发异常,并使用@Transactional 注释的另一种方法将错误记录到数据库中。无论出于何种原因,此过程似乎会导致游标泄漏,最终累加并触发 ORA-01000 open cursor limit exceeded 错误,导致线程停止处理任何内容。

        在同一代码中运行的 OracleDataSource 似乎不会泄漏游标,因此不会导致此问题。

        这是一个非常奇怪的场景,但它表明在具有这种结构的应用程序中使用 UCP 还为时过早。

        【讨论】:

          【解决方案5】:

          我也在测试 UCP,发现自己在基于线程池的应用程序中遇到了性能问题。最初,我尝试了 OracleDataSource,但在将其配置为批处理时遇到了麻烦。我在连接中不断收到 NullPointerExceptions,这让我相信我有某种连接泄漏,但只有在某些应用程序中,我们管理的其他应用程序不是面向批处理的 OracleDataSource 运行良好。

          根据这篇文章和我发现的其他一些研究该主题的文章,我尝试了 UCP。我发现通过足够的调整,我可以摆脱连接样式错误上的关闭连接/NullPointerExceptions,但是垃圾收集受到了打击。长期 GC 会很快填满,并且在应用程序完成运行之前似乎永远不会释放。如果负载真的很重,这有时可能需要一天或更长时间。我还注意到,处理数据也需要更长的时间。我将它与现在已贬值的 OracleCacheImpl 类(我们目前在生产中使用,因为它仍然“正常工作”)进行比较,它使用了 UCP 执行的 GC 内存的三分之一,并且处理文件的速度要快得多。在所有其他应用程序中,UCP 似乎工作得很好,几乎可以处理我扔给它的所有东西,但是线程池应用程序是一个主要应用程序,我不能在生产中冒 GC 异常的风险。

          【讨论】:

            【解决方案6】:

            如果您使用连接验证,隐式连接缓存的性能要比 UCP 好很多。这对应于 bug 16723836,计划在 12.1.0.2 中修复。

            UCP 池的获取/返回成本越来越高 随着并发负载的增加而连接。测试对比oracle 隐式连接缓存、tomcat 的池化和 UCP。 3个都是 配置为允许最多 200 个连接,最少 20 个连接和 初始大小为 2。所有 3 个都配置为将连接验证为 它们被从池中移除。 tomcat 池使用语句“select sysdate from dual”进行验证。

            这些结果是在具有 64 个逻辑内核(32 个物理内核)和 128 GB 内存的 64 位 RedHat 节点上得出的。

            在 5 个并发线程时,UCP 是最慢的,但完全连接管理 时间(获取和关闭)平均不到 1 毫秒。 随着并发的增加,UCP 越来越落后于 其他解决方案:

            25 Threads:
            Implicit: 0.58ms
            Tomcat: 0.92ms
            UCP: 1.50ms
            
            50 Threads:
            Implicit: 0.92ms
            Tomcat: 1.60ms
            UCP: 6.80ms
            
            100 Threads:
            Implicit: 2.60ms
            Tomcat: 3.20ms
            UCP: 21.40ms
            
            180 Threads:
            Implicit: 13.86ms
            Tomcat: 15.34ms
            UCP: 40.70ms
            

            【讨论】:

              【解决方案7】:

              在 Spring Bean.xml 中使用 UCP 有两种可能的方式。

              对于由某个文件设置的 db.properties,然后加载它然后使用其中之一:

              <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
              
                  <property name="location">
                      <value>classpath:resources/db.properties</value>
                  </property>
              </bean>
              

              第一个带有 oracle.ucp.jdbc.PoolDataSourceImpl :-

              <bean id="dataSource" class="oracle.ucp.jdbc.PoolDataSourceImpl">
              
                  <property name="URL" value="${jdbc.url}" />
                  <property name="user" value="${jdbc.username}" />
                  <property name="password" value="${jdbc.password}" />
              
                  <property name="validateConnectionOnBorrow" value="true"/>
              
                  <property name="connectionFactoryClassName" value="oracle.jdbc.pool.OracleDataSource" />
                  <property name="connectionPoolName" value="TEST_POOL" />
                  <property name="minPoolSize" value="10" />
                  <property name="maxPoolSize" value="20" />
                  <property name="initialPoolSize" value="12" />
              </bean>
              

              第二个是 oracle.ucp.jdbc.PoolDataSourceFactory :-

               <bean id="dataSource" class="oracle.ucp.jdbc.PoolDataSourceFactory"  
                   factory-method="getPoolDataSource">        
                  <property name="URL" value="${jdbc.url}" />
                  <property name="user" value="${jdbc.username}" />
                  <property name="password" value="${jdbc.password}" />
              
                  <property name="validateConnectionOnBorrow" value="true"/>
              
                  <property name="connectionFactoryClassName" value="oracle.jdbc.pool.OracleDataSource" />
                  <property name="connectionPoolName" value="TEST_POOL" />
                  <property name="minPoolSize" value="10" />
                  <property name="maxPoolSize" value="20" />
                  <property name="initialPoolSize" value="12" />
              </bean>
              

              就是这样:) 这是详细文档的链接: https://docs.oracle.com/cd/E11882_01/java.112/e12265/connect.htm#CHDDCICA

              【讨论】:

                【解决方案8】:

                我试过ucp,性能更好……可能是关键在用这个

                oracle.ucp.jdbc.PoolDataSource ds = (oracle.ucp.jdbc.PoolDataSource)envContext.lookup(url_r);
                MyConnectionLabelingCallback callback = new MyConnectionLabelingCallback();
                ds.registerConnectionLabelingCallback( callback );
                
                
                Properties label = new Properties();
                label.setProperty(pname, KEY);
                conn = ds.getConnection(label);
                

                这有助于借用连接并且永远不会关闭它..所以性能很棒

                回调类的代码是

                public class MyConnectionLabelingCallback
                implements ConnectionLabelingCallback {
                
                      public MyConnectionLabelingCallback()
                      {
                      }
                
                      public int cost(Properties reqLabels, Properties currentLabels)
                      {
                
                        // Case 1: exact match
                        if (reqLabels.equals(currentLabels))
                        {
                          System.out.println("## Exact match found!! ##");
                          return 0;
                        }
                
                        // Case 2: some labels match with no unmatched labels
                        String iso1 = (String) reqLabels.get("TRANSACTION_ISOLATION");
                        String iso2 = (String) currentLabels.get("TRANSACTION_ISOLATION");
                        boolean match =
                          (iso1 != null && iso2 != null && iso1.equalsIgnoreCase(iso2));
                        Set rKeys = reqLabels.keySet();
                        Set cKeys = currentLabels.keySet();
                        if (match && rKeys.containsAll(cKeys))
                        {
                          System.out.println("## Partial match found!! ##");
                          return 10;
                        }
                
                        // No label matches to application's preference.
                        // Do not choose this connection.
                        System.out.println("## No match found!! ##");
                        return Integer.MAX_VALUE;
                      }
                
                      public boolean configure(Properties reqLabels, Object conn)
                      {
                
                          System.out.println("Configure################");
                        try
                        {
                          String isoStr = (String) reqLabels.get("TRANSACTION_ISOLATION");
                          ((Connection)conn).setTransactionIsolation(Integer.valueOf(isoStr));
                          LabelableConnection lconn = (LabelableConnection) conn;
                
                          // Find the unmatched labels on this connection
                          Properties unmatchedLabels =
                           lconn.getUnmatchedConnectionLabels(reqLabels);
                
                          // Apply each label <key,value> in unmatchedLabels to conn
                          for (Map.Entry<Object, Object> label : unmatchedLabels.entrySet())
                          {
                            String key = (String) label.getKey();
                            String value = (String) label.getValue();
                            lconn.applyConnectionLabel(key, value);
                          }
                        }
                        catch (Exception exc)
                        {
                
                          return false;
                        }
                        return true;
                      }
                    }
                

                【讨论】:

                  猜你喜欢
                  • 2015-09-09
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-10-31
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-08-18
                  • 1970-01-01
                  • 2017-02-12
                  相关资源
                  最近更新 更多