Здравствуйте, понимаю, что мой вопрос в общем-то банальный, тем не менее пока разобраться до конца своими силами не выходит.
Итак, имеем веб-приложение. В качестве инфраструктуры бэк-енда Spring + JdbcTemplate + c3p0 как пул соединений + Postgres. Некоторое время назад время от времени в логи пула начали падать сообщения об исключениях. Я поставил ограничение на время жизни коннекта в пуле достаточно маленькое (15 минут) и вот что увидел в логах.
То бишь соединение прибивалось пулом, но в будущем снова начинало им выдаваться и соо-но валилось со следующим stack trace
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
16:51:29,213 DEBUG http-8081-6 NewPooledConnection:handleThrowable:430 - com.mchange.v2.c3p0.impl.NewPooledConnection@74e49974 handling a throwable.
org.postgresql.util.PSQLException: Connection is closed. Operation is not permitted.
at org.postgresql.core.QueryExecutor.executeV3(QueryExecutor.java:115)
at org.postgresql.core.QueryExecutor.execute(QueryExecutor.java:100)
at org.postgresql.core.QueryExecutor.execute(QueryExecutor.java:43)
at org.postgresql.jdbc1.AbstractJdbc1Statement.execute(AbstractJdbc1Statement.java:517)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:50)
at org.postgresql.jdbc1.AbstractJdbc1Statement.executeQuery(AbstractJdbc1Statement.java:233)
at org.postgresql.jdbc1.AbstractJdbc1Statement.executeQuery(AbstractJdbc1Statement.java:221)
at com.mchange.v2.c3p0.impl.NewProxyStatement.executeQuery(NewProxyStatement.java:35)
at org.springframework.jdbc.core.JdbcTemplate$1QueryStatementCallback.doInStatement(JdbcTemplate.java:443)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:396)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:458)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:466)
at org.springframework.jdbc.core.JdbcTemplate.queryForList(JdbcTemplate.java:497)
at ru.vsopen.system.db.DBExplorer.select(DBExplorer.java:369)
at ru.vsopen.common.service.messaging.domain.PrivateMessage.getUnreadMessagesCount(PrivateMessage.java:98)
at ru.vsopen.common.service.messaging.model.MessagingModel.getUnreadCount(MessagingModel.java:374)
at ru.vsopen.base.model.SideBarWidget.countMessages(SideBarWidget.java:201)
at ru.vsopen.base.model.SideBarWidget.execAction(SideBarWidget.java:89)
at ru.vsopen.system.io.service.widget.AbstractfxWidget.execCurrentAction(AbstractfxWidget.java:202)
at ru.vsopen.system.io.service.widget.AbstractfxWidget.invokeCurrentAction(AbstractfxWidget.java:292)
at ru.vsopen.system.io.service.WidgetManager.ifUseOnlyInvoked(WidgetManager.java:922)
at ru.vsopen.system.io.service.WidgetManager.invokeWidgets(WidgetManager.java:615)
at ru.vsopen.system.io.service.WidgetManager.exec(WidgetManager.java:236)
at ru.vsopen.system.io.controllers.WidgetListController.handleRequestInternal(WidgetListController.java:162)
at ru.vsopen.system.io.controllers.AbstractController.handleRequest(AbstractController.java:43)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.blackzorro.SmartFileUploads.doFilter(SmartFileUploads.java:240)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
Короче что-то не отпускает само соединение, всвязи с этим хочу опубликовать куски кода системы и задать несколько вопросов.
В качестве работы с БД используется JdbcTemplate обёртка от Spring. бин пула хранится в контексте
Описание бина выглядит следующим образом:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="100" />
<property name="acquireIncrement" value="5" />
<property name="unreturnedConnectionTimeout" value="600" />
<property name="debugUnreturnedConnectionStackTraces" value="true" />
<property name="testConnectionOnCheckin" value="true" />
<property name="idleConnectionTestPeriod" value="300" />
<property name="preferredTestQuery" value="select 1;" />
<property name="maxConnectionAge" value="900" />
</bean>
Конструктор нашего класса DBExplorer, в котором мы получаем DataSource
1.
2.
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
this.dataSource = (DataSource)ctx.getBean("dataSource");
Затем оперируем ключевыми методами startTransaction, commit, rollback, select
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
public TransactionStatus startTransaction(int level) throws SQLException {
this.txManager = new DataSourceTransactionManager((DataSource)this.dataSource);
DefaultTransactionDefinition def = new DefaultTransactionDefinition(
TransactionDefinition.PROPAGATION_REQUIRED
);
def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
return txManager.getTransaction(def);
}
public void commit(TransactionStatus status) throws SQLException {
this.txManager.commit(status);
}
public void rollback(TransactionStatus status) throws SQLException {
this.txManager.rollback(status);
}
public List<HashMap<String, Object>> select(String query, Object[] args) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(this.dataSource);
return jdbcTemplate.queryForList(query, args);
}
Вопросы следующие, кто работал с c3p0, опция destroy-method со значением "close" означает, что соединения будут закрыты, а конкретно когда?
Не может ли быть таких проблем из-за того, что DataSource берется в DBExplorer, а последний хранится постоянно в сессии. Замечу, что JdbcTemplate принимает везде DataSource и явно Connection нигде не фигурирует, закрывается ли он при commit, rollback для меня вопрос. Но по идее должен?
И вообще как можно избежать этой гадости? :) Наверняка кто-то плотно работал с похожей системой (JdbcTemplate + c3p0)