Я хочу обернуть некоторый код JDBC в свои и разные классы.Таким образом, ресурс создается в этих классах, набор результатов возвращается.Если клиент готов, все открытые ресурсы в этой цепочке должны быть закрыты.
Я написал следующее, но я не уверен, что это достаточно правильно и проще всего.
Я строю строку SQL для вставки строки данных.
Из моего источника данных (пул хикари) я получаю соединение с базой данных.Затем я создаю подготовленный оператор, выполняю его и получаю ResultSet
обратно.
Этот набор результатов я возвращаю вызывающей стороне.
Соединение и подготовленный оператор должны оставаться открытыми, пока вызывающая сторона не будет готова с этим возвращенным набором результатов
public DbResult insert(int cache, String shema, String table, LinkedHashMap<String, Object> data, boolean returnAutoCreate) throws SQLException
{
//building sql-string or take it from my cache
//...
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try
{
connection = ds.getConnection();
preparedStatement = connection.prepareStatement(sqlString);
int i = 0;
for (Object value : data.values())
{
preparedStatement.setObject(i++, value);
}
preparedStatement.executeUpdate();
resultSet = preparedStatement.getResultSet();
DbResult dbResult = new DbResult(connection, preparedStatement, resultSet);
return dbResult;
}
catch (Exception e)
{
try
{
if (resultSet != null) resultSet.close();
}
catch (Exception e2)
{
e.addSuppressed(e2);
}
try
{
if (preparedStatement != null) preparedStatement.close();
}
catch (Exception e2)
{
e.addSuppressed(e2);
}
try
{
if (connection != null) connection.close();
}
catch (Exception e2)
{
e.addSuppressed(e2);
}
throw e;
}
}
Вот мой класс DbResult
class DbResult implements AutoCloseable
{
private final ResultSet rs;
private final PreparedStatement ps;
private final Connection conn;
public DbResult(Connection conn, PreparedStatement ps, ResultSet rs)
{
this.conn = conn;
this.ps = ps;
this.rs = rs;
}
@Override
public void close() throws SQLException
{
try (conn; ps; rs;){}
}
public ResultSet getResultSet()
{
return rs;
}
}
Издесь код клиента / вызывающего абонента
DatabaseHelper databaseHelper = new DatabaseHelper(ds, defaultShema);
try(DbResult result = databaseHelper.insert(1001, defaultShema, "test", new LinkedHashMap<>(), true);)
{
//do sth with result
}
В своем методе вставки я добавил, что try catch, потому что если что-то не получается, я должен закрыть ресурсы.
Если проблем нет,Я добавляю ресурсы к своему DbResult
объекту, и там я закрываю ресурсы с помощью close()
-метода.При этом я использую try-with, потому что если в этой цепочке одно закрытие завершается неудачно, то другие все еще закрываются, и исключение корректно пересылается.
У моего вызывающего абонента я также использую try-with, который вызывает этот close()
-метод в DbResult после того, как я закончу с результатом.
Но это много кода, особенно конструкция try-catch в моем методе вставки.
Я не уверен, есть ли более простой или лучший способ сделать это.
У меня есть еще один вопрос:
Я мог бы кешировать результат, поэтому у меня нетпозаботиться о закрытии этого ресурса за пределами моего DatabaseHelper
класса.
Существует CachedRowSet
.Но я не уверен, насколько это дорого.Копирует ли это также метаинформацию?
Я думаю, нормальный ResultSet
сначала получает данные, если я к ним обращаюсь: метаданные, данные строки: строка за строкой?
что это хорошая идея для кэширования данных в ArrayList из Hashmaps?
Arraylist -> Rows
HashMap -> столбцы по имени -> значение
Так что, если я сделаю это, я могу закрытьвсе ресурсы немедленно.
-> Мне не нужно заботиться о том, что закрытие за пределами моего DatabaseClass
-> пул восстанавливает соединение быстрее
Однако, возможно, я получаю данные, которые яне нужны (например, метаданные).
Кроме того, копировать мои данные в конструкцию ArrayList-> Hashmap дорого.
Итак, какие у вас есть идеи?того, что;какая лучшая практика?