Что такое транзакционная процедура
Что проверяют
Понимаете ли вы, где проходит граница транзакции и кто ею управляет: процедура в базе, код сервиса или контейнер. Для java-разработчика это заодно вопрос о том, как логика на стороне СУБД стыкуется с транзакциями приложения.
Как отвечать
Транзакционная процедура это хранимая процедура, внутри которой набор операций выполняется как одна логическая единица: есть явное начало, фиксация и откат при ошибке. Ценность не в том, что код лежит в базе, а в том, что граница атомарности целиком внутри процедуры.
CREATE PROCEDURE transfer(src int, dst int, amount numeric) AS $$
BEGIN
UPDATE accounts SET balance = balance - amount WHERE id = src;
UPDATE accounts SET balance = balance + amount WHERE id = dst;
END;
$$ LANGUAGE plpgsql;Дальше ACID по существу: атомарность даёт откат целиком, изоляция задаётся уровнем и определяет, что видят соседние транзакции. Полезно добавить деталь: в PostgreSQL процедура, в отличие от функции, умеет фиксировать транзакцию внутри себя.
Вторая половина сильного ответа про приложение: ту же роль играет метод с аннотацией @Transactional, где границу открывает и закрывает менеджер транзакций. Правило одно: одна бизнес-операция это одна граница, вложенных транзакций нет, частичный откат делается точками сохранения.
Где спотыкаются
Называют транзакционной любую хранимую процедуру. Если управления границей внутри нет, каждый оператор фиксируется сам по себе, и после сбоя на середине половина изменений останется в базе.
Гасят исключение внутри транзакционного метода и удивляются результату. В типовой настройке откат срабатывает на непроверяемых исключениях, для проверяемых его надо объявлять явно, а пойманное и проглоченное исключение оставляет транзакцию помеченной на откат. Отдельная ловушка: вызов транзакционного метода из соседнего метода того же класса идёт мимо прокси, и транзакции просто нет.
Растягивают границу на внешний мир: внутри открытой транзакции ходят по HTTP в чужой сервис, отправляют письмо, ждут файл. Всё это время держатся соединение и блокировки строк. Внешние вызовы выносятся за фиксацию, а надёжность обеспечивается таблицей исходящих сообщений.