简体   繁体   English

Oracle数据源连接池不能与Spring和JDBCTemplate一起使用

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

Question: Lot of active unclosed physical connections with database even with connection pooling. 问题:即使有连接池,也有很多与数据库的活动未闭合物理连接。 Can someone tell me why is it so? 有人能告诉我为什么会这样吗?

I configured the connection pool settings using oracle.jdbc.pool.OracleDataSource . 我使用oracle.jdbc.pool.OracleDataSource配置了连接池设置。 However it seems the physical connections are not getting closed after use. 然而,似乎物理连接在使用后没有关闭。 I thought, Since it is connection pooling, the connections will be reused from the pool, so so many physical connections will not be made, but thats not what is happening now! 我想,由于它是连接池,连接将从池中重用,因此将不会进行如此多的物理连接,但这不是现在发生的事情!

There are 100+ active physical connections in the database generating from the application [not from plsql developer or any such client tools], due to which it kicks off TNS error while trying to do write operations on database, where as read operations are fine even with large number of active connections. 从应用程序生成的数据库中有100多个活动物理连接[不是来自plsql开发人员或任何此类客户端工具],因此在尝试对数据库执行写入操作时会启动TNS错误,因为读取操作甚至都很好具有大量活动连接。

Here is the Spring configuration, 这是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>

The SQL that returned the 100+ active connections is , 返回100多个活动连接的SQL是,

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

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

Thanks to @Evgeniy Dorofeev. 感谢@Evgeniy Dorofeev。

Solution in detail : 详细解决方案:

  1. The connectionCache was enabled, but the properties were not set. connectionCache已启用,但未设置属性。 Set the properties as written below, 设置如下所示的属性,

` `

<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>

` `

Now, for every operation in the application that requires a connection, it will try to get from the pool if available and ready to use, but is guaranteed that the database will have maximum of only 10 active physical connections. 现在,对于需要连接的应用程序中的每个操作,它将尝试从池中获取并且可以使用,但保证数据库最多只有10个活动物理连接。 Any attempt to get a extra physical connection will lead to a database error at the application side. 任何获得额外物理连接的尝试都会导致应用程序端出现数据库错误。

  1. Even if you have set the connectionCache , make sure your application is not explicitly trying to get a connection, like 即使您已设置connectionCache ,也请确保您的应用程序未明确尝试获取连接,例如

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

This is alarming, JDBCTemplate doesnt manage the closing of this connection. 这是令人担忧的,JDBCTemplate不会管理此连接的关闭。 Hence you have to close by yourself after use, otherwise the physical connection will still be active and unclosed even after use. 因此,您必须在使用后自行关闭,否则即使在使用后,物理连接仍将处于活动状态且未关闭。 So next time you call this again, it try to get a new physical connection , and remain unclosed, resulting in piling up of active connections until the maxLimit is reached. 因此,下次再次调用它时,它会尝试获取新的物理连接,并保持未闭合状态,从而导致堆积活动连接,直到达到maxLimit。

The connection might be explicity needed when you want to pass it as a parameter to some other function, say in the case of an ArrayDescriptor [if you talk to PLSQL Stored procedures that has IN parameter to accept an array of values , an array of Varchar or array of RAW]. 当你想将它作为参数传递给其他函数时,可能需要明确连接,例如在ArrayDescriptor的情况下[如果你谈到具有IN参数的PLSQL存储过程接受一个值数组,一个Varchar数组]或RAW数组]。 If you need to create a ArrayDescriptor, 如果需要创建ArrayDescriptor,

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

Hence do a connection.close() explicity here. 因此在这里做一个connection.close()表达。

Additional info: 附加信息:

Connection connection = getJdbcTemplate().getDataSource().getConnection()
  • This attempts to establish a connection with the data source that this DataSource object represents. 这会尝试与此DataSource对象表示的数据源建立连接。

Calling this line of code - once, will attempt to establish a new connection. 调用这行代码 - 一次,将尝试建立新连接。 Calling again, will establish a second connection. 再次呼叫,将建立第二个连接。 For each request, it will create a new connection!.So If your maxLimit is 10, Until there are 10 active physical connections in the database, the call will be successful, but note that all the connections are active [not closed]. 对于每个请求,它将创建一个新连接!。如果你的maxLimit是10,直到数据库中有10个活动物理连接,呼叫将成功,但请注意所有连接都是活动的[未关闭]。

So lets say now there are 10 active db connections, as maxLimit is set to 10. 因此,现在假设有10个活动数据库连接,因为maxLimit设置为10。

So any requests that requires a database operation, that would go through the normal route of accessing a connection via the JDBCTemplate will be picking up the already established connection [from the 10 connections] 因此,任何需要数据库操作的请求(通过JDBCTemplate将通过正常的访问连接的路径)将获取已经建立的连接[来自10个连接]

However any request that calls this code getJdbcTemplate().getDataSource().getConnection() to access a connection will attempt to establish a NEW connection, and will fail, resulting in exception. 但是,调用此代码getJdbcTemplate().getDataSource().getConnection()来访问连接的任何请求都将尝试建立新连接,并且将失败,从而导致异常。

The only way to resolve this is to explicitly close the connection when we explicitly create the connection. 解决此问题的唯一方法是在显式创建连接时显式关闭连接。 ie calling connection.close() When we don't explicitly create the connection, and when it is managed by Spring, then Spring will take care of closing the connections too. 即调用connection.close()当我们没有显式创建连接时,以及当它由Spring管理时,Spring也将负责关闭连接。 In the case of using Oracle Data Source pooling along with JDBCTemplate , closing the connection[returning the connections to the pool] is managed by Spring. 在使用Oracle数据源池和JDBCTemplate的情况下,关闭连接[返回池的连接]由Spring管理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM