Реализация AutoCloseable - как узнать, произошло ли исключение в блоке try?
У нас есть класс, который мы написали, который открывает соединение с сервером. Когда вы закончите с этим, вы должны либо сказать это commit
если все прошло успешно, или скажите это rollback
если что-то пошло не так. Так что сейчас у нас есть много мест в нашем коде, которые выглядят так:
OurConnectionClass conn = null;
try {
conn = OurConnectionClass(parameters);
// Do some stuff here...
conn.commit();
} catch (Throwable t) {
if (conn != null) {
conn.rollback();
}
throw t;
}
Если вы забудете выполнить фиксацию или откат, немедленных проблем не возникнет, но в итоге вы исчерпаете пул соединений, а затем должны выяснить, где вы допустили ошибку.
Я хотел бы найти способ так OurConnectionClass
инвентарь AutoClosable
так что я мог бы сделать что-то вроде этого вместо этого:
try (OurConnectionClass conn = new OurConnectionClass(parameters)) {
// Do some stuff here...
}
Я чувствую, что должен быть способ сделать это, но я этого не вижу. AutoCloseable
только вызывает close
метод, без аргументов, переданных ему. Насколько я вижу, нет никакого способа узнать, вызывается ли close, потому что конец блока try был успешно достигнут или потому что было сгенерировано исключение.
3 ответа
При выполнении этого фрагмента.
try (OurConnectionClass conn = new OurConnectionClass(parameters)) {
// Do some stuff here...
conn.commit();
}
OurConnectionClass.close()
всегда будет вызываться после создания экземпляра. Так что вы можете просто добавить логику, чтобы проверить, был ли сделан коммит. Например, с boolean
флаг. После этого вы можете проверить в close()
метод, если соединение должно быть закрыто мирно или должно произойти откат:
public class OurConnectionClass implements AutoCloseable{
private boolean committed; // initialized to false
public void commit(){
// commit
committed = true;
}
public void close() throws Exception{
if(!committed){
// rollback
}
}
}
Я думаю, что семантика, которую вы хотите, заключается в том, что транзакция откатывается при закрытии, если только код, который использует явный OurConnectionClass, не вызывает OurConnectionClass.commit().
Тогда у вас нет никаких проблем, потому что ваш метод close, то просто нужно проверить, есть ли открытая транзакция. И если есть откат, то и лог ошибки.
Делай оба!
try (OurConnectionClass conn = new OurConnectionClass(parameters)) {
// Do some stuff here...
conn.commit();
} catch (Throwable t) {
conn.rollback();
throw t;
}
Закрываемый все еще автоматически закрывается (в неявном finally
блок), если материал взрывается.
Кстати, было бы лучше бросить исключение домена:
throw new MyStuffExploded(t);
потому что повторное выбрасывание исключения соединения позволяет деталям реализации просачиваться через контракт метода, который является формой соединения, что плохо.