使用 Spring 和 DBCP 处理 JDBC 连接的正确方法是什么?
我正在使用 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(...);
阅读了一些内容后,我发现了 maxWait、maxActive 和 maxIdle > BasicDataSource< 的属性/a> (来自 通用对象池)。问题来了。我不确定应该如何设置它们,从性能角度来看。据我所知,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,这样它就不会首先抛出异常。 maxActive
和 maxIdle
的默认值为 8(我不明白为什么);如果我将它们设置为 -1,则不再抛出异常,并且一切似乎都工作正常。
考虑到这个应用程序应该支持大量并发请求,是否可以将这些设置保留为无限?考虑到我收到的错误,Spring 实际上会管理我的连接吗?考虑到它已经死了,我应该切换到 C3P0 吗?
I'm using the Spring MVC to build a thin layer on top of a SQL Server database. When I began testing, it seems that it doesn't handle stress very well :). I'm using Apache Commons DBCP to handle connection pooling and the data source.
When I first attempted ~10-15 simultaneous connections, it used to hang and I'd have to restart the server (for dev I'm using Tomcat, but I'm gonna have to deploy on Weblogic eventually).
These are my Spring bean definitions:
<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 -->
And this is how I use them:
// 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(...);
After reading around a little bit, I found the maxWait
, maxActive
and maxIdle
properties for the BasicDataSource (from GenericObjectPool). Here comes the problem. I'm not sure how I should set them, performance-wise. From what I know, Spring should be managing my connections so I shouldn't have to worry about releasing them.
<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>
First, I set maxWait
, so that it wouldn't hang and instead throw an exception when no connection was available from the pool. The exception message was:
Could not get JDBC Connection; nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object
There are some long-running queries, but the exception was thrown regardless of the query complexity.
Then, I set maxActive and maxIdle so that it wouldn't throw the exceptions in the first place. The default values are 8 for maxActive
and maxIdle
(I don't understand why); if I set them to -1 there are no more exceptions thrown and everything seems to work fine.
Considering that this app should support a large number of concurrent requests is it ok to leave these settings to infinite? Will Spring actually manage my connections, considering the errors I was receiving? Should I switch to C3P0 considering it's kinda dead?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
DBCP
maxWait
参数应以毫秒为单位定义。30
毫秒的值非常低,请考虑将其增加到30000
毫秒,然后重试。DBCP
maxWait
parameter should be defined in milliseconds.30
ms is very low value, consider increasing it to30000
ms and try again.正如您已经发现的,默认 dbcp 连接池是 8 个连接,因此如果您想同时运行 9 个查询,其中一个将被阻止。我建议您连接到数据库并运行 exec sp_who2 ,这将显示已连接的内容、活动的内容以及是否有任何查询被阻止。然后,您可以确认问题是在数据库上还是在您的代码中。
只要您使用 Spring 的 JdbcTemplate 系列对象,您的连接就会按照您的预期进行管理,如果您想使用原始数据源,请确保使用 DataSourceUtils 获取连接。
另一项建议 - 在 Spring 3 之前,不要使用 JdbcTemplate,坚持使用 SimpleJdbcTemplate,您仍然可以使用 SimpleJdbcTemplate.getJdbcOperations(),但是你应该发现自己写得更好了使用泛型编写代码,并且无需创建 JdbcTemplate/NamedParameterJdbcTemplate 实例。
As you already found out, the default dbcp connection pool is 8 connections, so if you want to run 9 simultaneous queries one of them will be blocked. I suggest you connect to your database and run
exec sp_who2
which will show you what is connected, and active, and whether any queries are being blocked. You can then confirm whether the issue is on the db or in your code.As long as you are using Spring's JdbcTemplate family of objects your connections will be managed as you expect, and if you want to use a raw DataSource make sure you use DataSourceUtils to obtain a Connection.
One other suggestion - prior to Spring 3, don't ever using JdbcTemplate, stick to SimpleJdbcTemplate, you can still access the same methods using SimpleJdbcTemplate.getJdbcOperations(), but you should find yourself writing much nicer code using generics, and remove the need to ever create JdbcTemplate/NamedParameterJdbcTemplate instances.
让我们换个角度。
都可能是因为您正在查询的表或表中的记录已被锁定(被其他某个活动事务锁定),因此超时。
尝试从 SQLServer 客户端运行相同的查询,如果需要很长时间,那么您可以确定是表或记录锁导致了这种情况。
Let's change the perspective.
It could be because the table or the records in the table, which you are querying against has been locked (by some other active transaction) and hence it times out.
Try running the same query from SQLServer Client and if it takes a long time, then you can be sure that it is the table or record lock that is causing this.