我正在尝试在 Spring 应用程序中使用 BasicDataSource 与 JDBCTemplate 连接池。从我读过的所有内容来看,这应该非常简单:只需在 XML 中配置 BasicDataSource,将数据源注入 bean,然后在 setter 方法中创建一个新的 JDBCTemplate。
当我这样做时,我注意到我的表现很糟糕。所以后来我切换到 Spring 的 SingleConnectionDataSource,只是想看看会发生什么,我的性能变得更好了。我开始使用分析器工具进行调查,我注意到在使用 BasicDataSource 时,会为每个查询创建一个新连接。
进一步调查,我可以看到查询完成后连接在哪里关闭。特别是在 Spring 的 DataSourceUtil 类中:
public static void doReleaseConnection(Connection con, DataSource dataSource) throws SQLException {
if (con == null) {
return;
}
if (dataSource != null) {
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null && connectionEquals(conHolder, con)) {
// It's the transactional Connection: Don't close it.
conHolder.released();
return;
}
}
// Leave the Connection open only if the DataSource is our
// special SmartDataSoruce and it wants the Connection left open.
if (!(dataSource instanceof SmartDataSource) || ((SmartDataSource) dataSource).shouldClose(con)) {
logger.debug("Returning JDBC Connection to DataSource");
con.close();
}
}
我注意到的是“SmartDataSource”有一些特殊的逻辑,它使连接保持打开状态。这部分解释了我看到的行为:由于 SingleConnectionDataSource 实现了 SmartDataSource,因此连接没有关闭。但是,我认为通过使用 BasicDataSource,连接上的 close() 方法只会将连接返回到池中。但是,当我查看探查器中发生的情况时,实际上是在我的 sybase 连接上调用了 close 方法:不是我希望看到的任何类型的“池化连接包装器”。
最后一件事(这是我现在要研究的内容):我对一些查询使用 TransactionTemplate(涉及对数据库的提交),但简单的查询不在 transactionTemplate 中。我不知道这是否与问题有关。
编辑1:
好的,在完成项目后终于有更多时间进行调查,这是一个非常简单的测试,可以显示问题
public class DBConnectionPoolTest {
@Autowired
@Qualifier("myDataSource")
private DataSource dataSource;
@Test
public void test() throws Exception{
JdbcTemplate template = new JdbcTemplate(dataSource);
StopWatch sw = new StopWatch();
sw.start();
for(int i=0; i<1000; i++){
template.queryForInt("select count(*) from mytable");
}
sw.stop();
System.out.println("TIME: " + sw.getTotalTimeSeconds() + " seconds");
}}
这是我的两个数据源配置:
<bean id="myDataSource" class="org.springframework.jdbc.datasource.SingleConnectionDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
当我使用第一个配置运行测试时,大约需要 2.1 秒。当我使用第二种配置运行它时,大约需要 4.5 秒。我在 BasicDataSource 上尝试了各种参数,例如设置 maxActive=1 和 testOnBorrow=false,但没有任何区别。