Spring oracle 数据源不破坏连接

Spring oracle datasource does not destroy connection

我将 oracle.jdbc.pool.OracleDataSource 用于 Oracle 池连接,但连接似乎在数据库中保持活动状态。今天我在连接到 Oracle 数据库时遇到错误:

ORA-12516: TNS:listener could not find available handler with matching protocol stack

我们的数据库管理员告诉我,我的应用程序中有太多打开的连接处于 "IDLE" 模式。

我用的是ojdbc7:

<dependency>
    <groupId>com.oracle</groupId>
    <artifactId>ojdbc7</artifactId>
    <version>12.1.0.1</version>
</dependency>

Spring applicationContext.xml 文件:

<bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close"> 
    <property name="URL" value="${jdbc.url}" /> 
    <property name="user" value="${jdbc.username}" /> 
    <property name="password" value="${jdbc.password}" /> 
    <property name="connectionCachingEnabled" value="true" /> 
</bean>

DbConnect class:

import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class DbConnect {

  @Autowired
  private DataSource dataSource;

  public Connection getConnection() throws SQLException {
      return dataSource.getConnection();
  }
}

我还在我的 dao 级别中使用 jdk7 try-with-resources 语法进行连接:

 @Autowired
 private DbConnect dbConnect;

 public List<User> getAllUsers() {
    List<User> list = new ArrayList<>();

    try(Connection connection = dbConnect.getConnection()) {
        try(PreparedStatement preparedStatement = connection.prepareStatement("select * from V_USERS t")) {
            try(ResultSet resultSet = preparedStatement.executeQuery()) {
                while(resultSet.next()) {
                    list.add(RowFetcher.fetchUser(resultSet));
                }
            }
        }
    }
    catch(Exception e) {
        log.error(e.getMessage(), e);
    }

    return list;
}

无法弄清楚实际问题出在哪里。我应该使用 c3p0 而不是 OracleDataSource 吗? ojdbc7 是否有错误或我的代码有错误?

提前致谢!

您可以设置数据源限制属性来控制缓存的大小。

<property name="connectionCacheProperties">
  <props>
     <prop key="MinLimit">${jdbc.limit.min}</prop>
     <prop key="MaxLimit">${jdbc.limit.max}</prop>
     <prop key="InitialLimit">${jdbc.limit.init}</prop>
  </props>
</property>

尝试使用不同的数据源org.apache.commons.dbcp.BasicDataSource。对我有用

池的全部意义在于保持连接打开。但是我不确定 OracleDataSource 是一个实际的池还是您需要 OracleConnectionPoolDataSource

我建议使用 HikariCP. The page on configuration options 和默认值,而不是使用普通的 Oracle 池。

在那种情况下,您的数据源将类似于

<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"> 
    <property name="datasourceClassName" value="oracle.jdbc.pool.OracleDataSource" />
    <property name="dataSourceProperties">
        <props>
            <prop key="URL" value="${jdbc.url}" /> 
            <prop key="user" value="${jdbc.username}" /> 
            <prop key="password" value="${jdbc.password}" /> 
            <prop key="connectionCachingEnabled" value="true" />
        </props>
    </property>
</bean>

注意:还有一个关于池大小的很好的 page(实际上来自 Oracle!)。

我还建议,为了清理您的代码,删除 DbConnect class 并注入(或创建)一个 JdbcTemplate 来使用而不是使用普通连接。节省您管理所有 JDBC 个对象的时间。

private final JdbcTemplate jdbcTemplate;

@Autowired
public YourRepository(DataSource ds) {
    this.jdbcTemplate=new JdbcTemplate(ds);
}

public List<User> getAllUsers() {
    List<User> list = new ArrayList<>();
    return this.jdbcTemplate("select * from V_USERS t", new RowMapper() {
        public User mapRow(ResultSet rs, int row) throws SQLException {
            return RowFetcher.fetchUser(rs);
        }
    });
}

我们有通用连接池 (UCP),它是 Java 连接池。
有关更多配置详细信息,请参阅 UCP with Spring