使用Spring和JDBCTemplate时,Oracle数据源连接池无法正常工作

3

问题:即使使用连接池技术,仍有大量未关闭的数据库物理连接。有人能告诉我为什么吗?

我使用oracle.jdbc.pool.OracleDataSource配置了连接池设置。然而,似乎在使用后物理连接并没有被关闭。 我认为,既然是连接池,那么连接应该从池中重复使用,因此不会建立那么多物理连接, 但现在情况并非如此!

由于应用程序造成了100多个活动物理连接[而非plsql developer或其他客户端工具],导致在尝试对数据库进行写操作时出现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'
2个回答

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

谢谢你提到默认值,+1。让我阅读更多关于它并缓存。 - spiderman
我已经详细地发布了解决方案。 - spiderman

1

感谢@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不管理此连接的关闭。因此,在使用后,您必须自己关闭它,否则物理连接仍然处于活动状态且未关闭。下一次再调用此操作时,它会尝试获取新的物理连接,并保持未关闭状态,导致堆积的活动连接直到达到最大限制。

当您想将其作为参数传递给其他函数时(例如,在处理具有IN参数以接受值数组、Varchar数组或RAW数组的PLSQL存储过程中),可能需要显式获取连接。如果您需要创建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个活动的db连接,因为maxLimit设置为10。

因此,任何需要数据库操作的请求,都将通过正常路由访问JDBCTemplate来获取已经建立的连接[从10个连接中选择]

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

唯一解决方法是在我们显式创建连接时显式关闭连接。即调用 connection.close()。当我们没有明确创建连接并且由Spring管理时,Spring将负责关闭连接。在使用Oracle数据源池和 JDBCTemplate 时,关闭连接[返回到池中]由Spring进行管理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接