Есть ли какой-либо инструмент или метод, чтобы идентифицировать открытый ResultSet - PullRequest
2 голосов
/ 03 ноября 2010

В контексте Java-приложения, использующего SQLIte для сохранения данных, я использую драйвер Zentus JDBC. Таким образом, я использую пакет java.sql для доступа к моей базе данных.

Я сталкиваюсь с некоторыми странными (в среде с несколькими объектами Connection в одной базе данных) проблемами, и я почти уверен, что мои проблемы возникают из-за закрытого ResultSet.

Есть ли какой-либо инструмент или метод, позволяющий мне определить, где искать в моем исходном коде, чтобы найти эти незамкнутые объекты?

Редактировать Возможно, используется AspectJ ??

Ответы [ 4 ]

3 голосов
/ 04 ноября 2010

Кажется, что аспект может быть полезным.

Как насчет упаковки методов, которые возвращают набор результатов в аспекте. Что-то вроде:

execution(public java.sql.ResultSet+ java.sql.Statement+.*(..))

Другой аспект может отслеживать метод close в ResultSets. Может быть:

execution(public * java.sql.ResultSet.close())

Первый аспект, по возвращении каждого ResultSet, создаст новый объект Exception и сохранит его где-то в статической карте, используя хеш ResultSet в качестве ключа. Второй аспект, при закрытии результирующего набора, будет удалять исключение из карты, используя тот же хэш-код, что и ключ. В любое время на карте должен быть один экземпляр исключения для каждого открытого ResultSet. Из исключения вы можете получить трассировку стека, чтобы увидеть, где был открыт ResultSet.

Возможно, вы можете хранить более крупный объект, который включает исключение и некоторую другую контекстную информацию; время создания ResultSet и т. д.

2 голосов
/ 03 ноября 2010

Практическое предложение состоит в том, чтобы добавить некоторый отладочный код и создание «журнала» и закрыть наборы результатов в CSV-файл.Позже вы можете проверить этот файл и проверить, есть ли запись «close» для каждого «create».

Итак, если у вас есть служебный класс со статическими методами, который позволяет записывать строки в файл, вы можетесделайте это следующим образом:

 ResultSet rs = stmt.executeQuery(query);
 Util.writeln(rs.hashcode() + ";create"); // add this line whenever a 
                                         // new ResultSet is created

и

 rs.close();
 Util.writeln(rs.hashcode() + ";closed"); // add this line whenever a 
                                         // ResultSet is closed

Откройте файл CSV в Excel или любой другой программе для работы с электронными таблицами, отсортируйте таблицу и посмотрите, не закрыты ли наборы результатов.Если это так, добавьте больше отладочной информации, чтобы четко идентифицировать открытые наборы.


Кстати: перенос интерфейсов (например, JAMon) довольно прост, если у вас есть затмение или что-то еще, его кодирование вменее 15 минут.Вам нужно будет обернуть Connection, Statement (и PreparedStatement?) И ResultSet, обертку ResultSet можно было бы оборудовать для отслеживания и мониторинга создания и закрытия наборов результатов:

public MonitoredConnection implements Connection {
  Connection wrappedConnection = null;

  public MonitoredConnection(Connection wrappedConnection) {
    this.wrappedConnection = wrappedConnection;
  }

  // ... implement interface methods and delegate to the wrappedConnection

  @Override
  public Statement createStatement() {
    // we need MonitoredStatements because later we want MonitoredResultSets
    return new MonitoredStatement(wrappedConnection.createStatemet());
  }

  // ...
}

То же самое для MonitoredStatement и MonitoredResultSetMonitoredStatement вернет упакованные ResultSets):

public MonitoredStatement implements Statement {
  private Statement wrappedStatement = null;

  @Override 
  public ResultSet executeQuery(String sql) throws SQLException
     MonitoredResultSet rs = wrappedStatement.executeQuery(sql);
     ResultSetMonitor.create(rs.getWrappedResultSet()); // some static utility class/method
     return rs;
  }

  // ...
}

и

public MonitoredResultSet implements ResultSet {
  private ResultSet wrappedResultSet;

  @Override 
  public void close() {
     wrappedResultSet.close();
     ResultSetMonitor.close(wrappedResultSet); // some static utility class/method
  }

  // ...
}

В конце вам нужно всего лишь изменить одну строку в вашем коде:

Connection con = DriverManager.getConnection(ur);

до

Connection con = new MonitoredConnection(DriverManager.getConnection(ur));
1 голос
/ 03 ноября 2010

Должно быть относительно просто обработать ваш код АОП по вашему выбору.Несколько лет назад я использовал AspectWerkz для создания веб-приложения во время загрузки и сбора статистики по производительности.Кроме того, если вы используете инфраструктуру IOC, такую ​​как Spring, очень легко обернуть ваши источники данных и отслеживать вызовы getConnection () и т. Д.

1 голос
/ 03 ноября 2010

A Поиск Google указал мне прямо на JAMon . Это позволяет вам также контролировать соединения JDBC и курсоры.

Лично я бы проверил код и убедился, что все Заявление , PreparedStatement и ResultSet закрыты, когда они не нужны. Даже при использовании пула соединений в пул возвращаются только соединения JDBC, а операторы и ResultSet закрываются.

В этом примере показано, как добиться закрытия ResultSet и PreparedStatement при закрытии finally (для гарантии):

PreparedStatement ps = null;
ResultSet rs = null;
UserRequest request = null;

try {
 ps = getConnection().prepareStatement(SQL_RETRIEVE);
 ps.setLong(1, id);
 rs = ps.executeQuery();
 if (rs != null && rs.next()) {
  request = mapEntity(rs);
 }
} catch (SQLException e) {
 // TODO Auto-generated catch block
 throw new DAOException(e);
} finally {
 try {
  close(rs, ps);
 } catch (SQLException e) {
  // TODO Auto-generated catch block
  logger.error("Error closing statement or resultset.", e);
 }
}

Это мои 2 цента стоит ... надеюсь, это поможет вам.

...