Я пытаюсь использовать BasicDataSource для объединения соединений с JDBCTemplate в весеннем приложении. Из всего, что я прочитал, это должно быть действительно просто: просто сконфигурируйте BasicDataSource в XML, вставьте источник данных в bean-компонент, а в методе setter создайте новый JDBCTemplate.
Когда я это сделал, я заметил, что мое выступление было ужасным. Затем я переключился на SpringConnectionDataSource Spring, просто чтобы посмотреть, что произойдет, и моя производительность стала намного лучше. Я начал исследовать с помощью инструмента профилирования и заметил, что при использовании BasicDataSource для каждого запроса создается новое соединение.
Продолжая расследование, я вижу, где закрывается соединение после завершения запроса. В частности, в классе DataSourceUtil Spring:
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 для некоторых моих запросов (связанных с фиксацией в базе данных), но простые запросы не находятся внутри транзакции транзакции. Я не знаю, имеет ли это какое-либо отношение к проблеме или нет.
РЕДАКТИРОВАТЬ 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, но ничто не имеет значения.