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

时间:2010-08-19 19:32:36

标签: java spring jdbc connection-pooling dao

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

当我第一次尝试~10-15个同时连接时,它曾经挂起而且我必须重新启动服务器(对于我正在使用Tomcat,但我最终必须在Weblogic上部署)。 / p>

这些是我的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(...);

在阅读了一下之后,我找到了BasicDataSourcemaxWaitmaxActivemaxIdle属性(来自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:无法获取连接,池错误超时等待空闲对象

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

然后,我设置maxActive和maxIdle,这样它就不会抛出异常。 maxActivemaxIdle的默认值为8(我不明白为什么);如果我将它们设置为-1,则不会抛出更多异常,并且所有似乎都能正常工作。

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

3 个答案:

答案 0 :(得分:9)

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

答案 1 :(得分:6)

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

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

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

答案 2 :(得分:2)

让我们改变观点。

  

但抛出异常   无论查询复杂性如何

可能是因为您正在查询的表或表中的记录已被锁定(通过其他一些活动事务),因此它会超时。

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