Oracle 数据源连接池不适用于 Spring 和 JDBCTemplate

Oracle data source connection pooling not working used with Spring and JDBCTemplate

问题:即使有连接池,也有许多与数据库的活动未关闭物理连接。谁能告诉我为什么会这样?

我使用 oracle.jdbc.pool.OracleDataSource 配置了连接池设置。然而,物理连接似乎在使用后没有关闭。 我想,既然是连接池,连接会从池中重用,所以不会做那么多物理连接, 但现在不是这样!

从应用程序生成的数据库中有 100 多个活动物理连接[不是来自 plsql 开发人员或任何此类客户端工具], 由于它在尝试对数据库进行写操作时引发 TNS 错误, 即使有大量活动连接,读取操作也很好。

这里是Spring配置,

<bean id="oracleDataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close"
                                p:URL="${url}"
                                p:user="${username}"
                                p:password="${password}"
                                p:connectionCachingEnabled="true">
                                <property name="connectionProperties">
                                   <props merge="default">
                                      <prop key="AutoCommit">false</prop>
                                   </props>
                                </property>
</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
                                p:dataSource-ref="oracleDataSource" />

<bean id="transactionManager"
                                class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
                                p:dataSource-ref="oracleDataSource">
</bean>

返回 100 多个活动连接的 SQL 是,

select username, terminal,schemaname, osuser,program from v$session where username = 'grduser'

您应该配置连接缓存,隐式连接缓存的最大连接数的默认值是为数据库配置的最大数据库会话数。

感谢@Evgeniy Dorofeev。

详细解答:

  1. connectionCache 已启用,但未设置属性。 如下所示设置属性,

`

<bean id="oracleDataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close"
                                        p:URL="${url}"
                                        p:user="${username}"
                                        p:password="${password}"
                                        p:connectionCachingEnabled="true">
                                        <property name="connectionProperties">
                                           <props merge="default">
                                              <prop key="AutoCommit">false</prop>
                                           </props>
                                        </property>
         <property name="connectionCacheProperties">
                    <props>
                        <prop key="MinLimit">5</prop>
                        <prop key="MaxLimit">10</prop>
                        <prop key="InactivityTimeout">2</prop>
                    </props>
                </property>
     </bean>

`

现在,对于应用程序中需要连接的每个操作,如果可用并准备好使用,它会尝试从池中获取,但保证数据库最多只有 10 个活动物理连接。任何获得额外物理连接的尝试都将导致应用程序端出现数据库错误。

  1. 即使您设置了 connectionCache,也要确保您的应用程序没有明确尝试获取连接,例如

Connection connection = getJdbcTemplate().getDataSource().getConnection();

这令人担忧,JDBCTemplate 不管理此连接的关闭。所以使用后必须自己关闭,否则即使使用后物理连接仍处于活动状态且未关闭。因此,下次您再次调用它时,它会尝试获取新的物理连接,并保持未关闭状态,从而导致活动连接堆积,直到达到 maxLimit。

当你想将它作为参数传递给其他函数时,可能需要显式连接,比如在 ArrayDescriptor 的情况下[如果你与具有 IN 参数的 PLSQL 存储过程交谈以接受值数组, Varchar 数组或 RAW] 数组。如果需要创建 ArrayDescriptor,

ArrayDescriptor arrayDescriptor = ArrayDescriptor.createDescriptor(
                           "SOME_TYPE_NAME", connection );
ARRAY SQLArray= new ARRAY(arrayDescriptor, connection , arrayString);

因此在这里做一个 connection.close() 明确。

附加信息:

Connection connection = getJdbcTemplate().getDataSource().getConnection()
  • 这将尝试与此 DataSource 对象代表的数据源建立连接。

调用这行代码 - 一次,将尝试建立新连接。 再次调用,将建立第二个连接。对于每个请求,它都会创建一个新连接!所以如果你的 maxLimit 是 10, 直到数据库中有10个活跃的物理连接,调用才会成功,但是 请注意,所有连接都处于活动状态 [未关闭]。

假设现在有 10 个活动的数据库连接,因为 maxLimit 设置为 10。

所以任何需要数据库操作的请求都会通过 通过 JDBCTemplate 访问连接的正常路径将选择已经建立的连接[来自 10 个连接]

但是任何调用此代码 getJdbcTemplate().getDataSource().getConnection() 来访问连接的请求 将尝试建立新连接,但会失败,从而导致异常。

解决这个问题的唯一方法是在我们显式创建连接时显式关闭连接。 即调用 connection.close() 当我们没有显式创建连接,并且由 Spring 管理时,Spring 将负责关闭 连接也是。在使用 Oracle 数据源池以及 JDBCTemplate 的情况下,关闭连接[返回 到池的连接] 由 Spring 管理。