使用 Spring 和 DBCP 处理 JDBC 连接的正确方法是啥?

Posted

技术标签:

【中文标题】使用 Spring 和 DBCP 处理 JDBC 连接的正确方法是啥?【英文标题】:What's the proper way to handle JDBC connections with Spring and DBCP?使用 Spring 和 DBCP 处理 JDBC 连接的正确方法是什么? 【发布时间】:2011-04-01 07:56:46 【问题描述】:

我正在使用 Spring MVC 在 SQL Server 数据库之上构建一个薄层。当我开始测试时,它似乎不能很好地处理压力:)。我使用Apache Commons DBCP 来处理连接池和数据源。

当我第一次尝试约 10-15 个同时连接时,它曾经挂起,我必须重新启动服务器(对于开发,我使用的是 Tomcat,但我最终将不得不部署在 Weblogic 上)。

这些是我的 Spring bean 定义:

<bean id="dataSource" destroy-method="close"
      class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
    <property name="url" value="[...]"/>
    <property name="username" value="[...]" />
    <property name="password" value="[...]" />
</bean>

<bean id="partnerDAO" class="com.hp.gpl.JdbcPartnerDAO">
    <constructor-arg ref="dataSource"/>
</bean>

<!-- + other beans -->

这就是我使用它们的方式:

// in the DAO
public JdbcPartnerDAO(DataSource dataSource) 
    jdbcTemplate = new JdbcTemplate(dataSource);


// in the controller
@Autowired
private PartnerDAO partnerDAO;

// in the controller method
Collection<Partner> partners = partnerDAO.getPartners(...);

在阅读了一下之后,我发现了BasicDataSource 的maxWaitmaxActivemaxIdle 属性(来自GenericObjectPool)。问题来了。我不确定我应该如何设置它们,性能方面。据我所知,Spring 应该管理我的连接,所以我不必担心释放它们。

<bean id="dataSource" destroy-method="close"
      class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
    <property name="url" value="[...]"/>
    <property name="username" value="[...]" />
    <property name="password" value="[...]" />
    <property name="maxWait" value="30" />
    <property name="maxIdle" value="-1" />
    <property name="maxActive" value="-1" />
</bean>

首先,我设置了maxWait,这样它就不会挂起,而是在池中没有可用连接时抛出异常。异常消息是:

无法获得 JDBC 连接;嵌套异常是 org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object

有一些长时间运行的查询,但无论查询复杂度如何,都会引发异常。

然后,我设置 maxActive 和 maxIdle 以便它不会首先抛出异常。 maxActivemaxIdle 的默认值为 8(我不明白为什么);如果我将它们设置为 -1,则不会抛出更多异常,并且一切似乎都可以正常工作。

考虑到这个应用程序应该支持大量并发请求,是否可以将这些设置保留为无限?考虑到我收到的错误,Spring 会真正管理我的连接吗?考虑到它已经死了,我应该切换到C3P0 吗?

【问题讨论】:

如果您遇到任何异常,发布堆栈跟踪将有助于轻松识别问题,是否有任何长时间运行的查询您发现问题? 我已经用异常消息和一些额外信息更新了我的帖子。 【参考方案1】:

DBCP maxWait 参数应该以毫秒为单位定义。 30 ms 的值非常低,请考虑将其增加到 30000 ms 并重试。

【讨论】:

【参考方案2】:

正如您已经发现的那样,默认的 dbcp 连接池是 8 个连接,因此如果您想同时运行 9 个查询,其中一个将被阻止。我建议您连接到您的数据库并运行exec sp_who2,它将向您显示已连接和活动的内容,以及是否有任何查询被阻止。然后您可以确认问题是在数据库上还是在您的代码中。

只要您使用 Spring 的 JdbcTemplate 系列对象,您的连接就会按照您的预期进行管理,如果您想使用原始数据源,请确保使用 DataSourceUtils 来获取连接。

另一个建议 - 在 Spring 3 之前,不要使用 JdbcTemplate,坚持使用 SimpleJdbcTemplate,您仍然可以使用 SimpleJdbcTemplate.getJdbcOperations() 访问相同的方法,但是您应该发现自己使用泛型编写了更好的代码,并删除需要创建 JdbcTemplate/NamedParameterJdbcTemplate 实例。

【讨论】:

【参考方案3】:

让我们换个角度。

但是抛出了异常 无论查询复杂度如何

这可能是因为您查询的表或表中的记录已被锁定(被其他活动事务),因此超时。

尝试从 SQLServer 客户端运行相同的查询,如果需要很长时间,那么您可以确定是表或记录锁导致了这种情况。

【讨论】:

我明白你的意思,但是当我将数据源的 maxActivemaxIdle 参数设置为较大的值(或无限)时,问题完全消失了。正如异常消息所述,这使我认为问题出在 ConnectionPool 中。

以上是关于使用 Spring 和 DBCP 处理 JDBC 连接的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

spring02

spring配置DBCP数据连接

spring jdbc

jdbc spring 安全性,apache commons dbcp

spring+mybatis整合,org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class '${jd

mybatis为啥要使用dbcp