Ответ вслух Middle JDBC и транзакции обновлено

Транзакция на чистом JDBC

Вопрос

Как выполнить перевод денег между счетами на чистом JDBC так, чтобы он был атомарным и корректным при параллельных переводах?

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

Беру одно соединение из пула, выключаю autoCommit, выполняю оба UPDATE через PreparedStatement и вызываю commit, а в catch rollback и пробрасываю ошибку. Соединение закрываю в try-with-resources, чтобы оно вернулось в пул.

Что должно прозвучать в ответе

  • Одно соединение, setAutoCommit(false), commit и rollback в catch

  • try-with-resources для Connection и PreparedStatement

  • Блокировка строк: SELECT ... FOR UPDATE или атомарный UPDATE с проверкой баланса

  • Порядок блокировки строк по id, чтобы избежать дедлоков

  • Уровень изоляции и повтор при ошибке сериализации

  • Как это делает Spring @Transactional

Что могут спросить следом

  • Что будет, если упасть между двумя UPDATE?
  • Чем оптимистическая блокировка отличается от пессимистической?

Разбор

Беру одно соединение из пула, выключаю autoCommit, выполняю оба UPDATE через PreparedStatement и вызываю commit, а в catch rollback и пробрасываю ошибку. Соединение закрываю в try-with-resources, чтобы оно вернулось в пул. Атомарности мало, нужна корректность при параллельных переводах: списание делаю условным UPDATE accounts SET balance = balance - ? WHERE id = ? AND balance >= ? и проверяю число изменённых строк, либо сначала беру строки через SELECT ... FOR UPDATE. Чтобы два встречных перевода не устроили дедлок, блокирую счета в порядке возрастания id. При SERIALIZABLE обрабатываю ошибку сериализации повтором. В Spring всё это прячет @Transactional: он берёт соединение, выключает autocommit, привязывает соединение к потоку и коммитит или откатывает по результату метода.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.