У меня были (я думаю) проблемы с пулом соединений. В частности, в моих журналах отображается сообщение:
org.apache.tomcat.dbcp.pool2.impl.DefaultPooledObject$AbandonedObjectCreatedException: объект пула, созданный [время] с помощью следующего кода, не был возвращен в пул
Я проверил методы, перечисленные в трассировке стека, которые показывают журналы, но не смог найти виновника (я всегда закрываю ResultSet
, PreparedStatement
и Connection
в конце каждого метода).
У меня есть метод, который выполняет два запроса, возможно, я не выполняю его должным образом.
Его макет выглядит следующим образом:
ConnectionPool pool = ConnectionPool.getInstance();
Connection connection = pool.getConnection();
PreparedStatement ps = null;
PreparedStatement rowsPs = null;
ResultSet rs = null;
ResultSet rowsRs = null;
String query = "SELECT SQL_CALC_FOUND_ROWS ...";
String totalRowsQuery = "SELECT FOUND_ROWS() AS RowCount";
try {
ps = connection.prepareStatement(query);
[set ps params]
rs = ps.executeQuery();
[process rs]
rowsPs = connection.prepareStatement(totalRowsQuery);
rowsRs = rowsPs.executeQuery();
[process rowsRs]
} catch (SQLException e) {
[handle e]
} finally {
DBUtil.closeResultSet(rs);
[close rowsRs]
[close ps]
[close rowsPs]
[close connection]
}
Где пример метода DBUtils:
public static void closeResultSet(ResultSet rs)
{
try
{
if (rs != null)
rs.close();
}
catch (SQLException sqle)
{
sqle.printStackTrace();
}
}
Общий вид этого метода кажется приемлемым? Должен ли я обрабатывать соединение по-другому? Или это какой-то другой метод, который вызывает регистрацию ошибок?
Спасибо.
Дополнительная информация
Я также получаю SQLException
:
java.sql.SQLException: соединение com.mysql.jdbc.JDBC4Connection@[некоторое число] закрыто
в строке: rowsPs = connection.prepareStatement(totalRowsQuery);
Это означает, что где-то раньше соединение было закрыто. Я нигде явно не закрываю соединение. Возможно ли, что какой-то другой вызываемый метод доступа к данным каким-то образом закрывает соединение в этом методе? (pool.getConnection()
звонит dataSource.getConnection()
)
Обновление: я попытался использовать попытку с ресурсами, как было предложено, но проблема не устранена.
Класс ConnectionPool, на который есть ссылка в первом фрагменте кода выше:
public class ConnectionPool
{
private static ConnectionPool pool = null;
private static DataSource dataSource = null;
public synchronized static ConnectionPool getInstance()
{
if ( pool == null ) {
pool = new ConnectionPool();
}
return pool;
}
private ConnectionPool()
{
try {
InitialContext ic = new InitialContext();
dataSource = (DataSource)
ic.lookup([jdbc/dbName]);
}
catch (Exception e) {
e.printStackTrace();
}
}
public Connection getConnection()
{
try {
return dataSource.getConnection();
}
catch (SQLException sqle) {
sqle.printStackTrace();
return null;
}
}
public void freeConnection(Connection c)
{
try {
c.close();
}
catch (SQLException sqle) {
sqle.printStackTrace();
}
}
}
Дополнительный источник: элемент ресурса My Pool:
<Resource auth="Container" driverClassName="com.mysql.jdbc.Driver"
logAbandoned="true" maxActive="100" maxIdle="30" maxWait="10000"
removeAbandonedOnBorrow="true"
removeAbandonedTimeout="60" type="javax.sql.DataSource"
testWhileIdle="true" testOnBorrow="true"
validationQuery="SELECT 1 AS dbcp_connection_test"/>
Обновление: я включил журнал медленных запросов, но, несмотря на то, что снова выдается Exception
, журнал медленных запросов ничего не регистрирует (ни один запрос не занимает более 10 секунд).
Таким образом, похоже, дело не в том, что запрос занимает более 60 секунд.
Все еще неясно, что вызывает это.
finally
не работает? Никакие нисходящие линии выполняться не будут. Я бы просто закрыл соединение, потому что все разумные реализации JDBC будут каскадно закрывать все связанные с ним ресурсы. - person Marko Topolnik   schedule 06.10.2016finally
не будут работать? - person theyuv   schedule 06.10.2016try
и печатает трассировку стека, если возникает исключение. - person theyuv   schedule 06.10.2016pool.getConnection()
и освобождается с помощьюconnection.close()
, это инвариант пула. Так что вам лучше найти причину, по которой строкаconnection.close()
либо не достигается, либо завершается ошибкой. Или, как еще более экзотическое объяснение, переменнаяconnection
переназначается и исходное соединение разрывается. - person Marko Topolnik   schedule 06.10.2016DataSource
? Например, в рамках метода, подобного приведенному выше, я вызываю несколько других методов доступа к базе данных, которые имеют одинаковую общую структуру (каждый получает соединение, а затем закрывает его). Есть ли ограничение на количество подключений, которые я могу получить, пока другие еще открыты? - person theyuv   schedule 06.10.2016rs
иps
в попытку с ресурсами, но я не понимаю, как это что-то изменит. На данный момент эти ресурсы закрыты в блоке finally и обернуты операторами try-catch. - person theyuv   schedule 07.10.2016rs.close()
в блоке try and catch (я обновил вопрос с образцом этого кода). Не будет ли это означать, что даже еслиrs.close()
завершится ошибкой, код просто поднимется со следующей строки в блоке finally (т. е. закроет rowRs), а не выйдет из всего метода? - person theyuv   schedule 07.10.201660
с, попробуйте увеличитьremoveAbandonedTimeout
до300
- person Nicolas Filotto   schedule 26.10.20161-2
секунды, занять более60
секунд? - person theyuv   schedule 26.10.2016pool.getConnection()
? Попробуйте и синхронизировать его. - person Palcente   schedule 31.10.2016Connection connection
является локальной переменной метода? Можешь сделатьfinal
на всякий случай? - person Roman   schedule 02.11.2016