Реализация 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);

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

Другие вопросы по тегам