[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"question-jdbc-kak-upravlyat-tranzaktsiyami-v-jdbc":3},{"id":4,"slug":5,"topicId":6,"topicSlug":7,"topicName":8,"topicEmoji":9,"question":10,"answer":11,"codeLang":12,"codeSrc":12,"important":12,"commonMistakes":12,"modernUsage":12,"difficulty":13,"tags":14,"related":17,"progress":18,"seo":19},1181,"kak-upravlyat-tranzaktsiyami-v-jdbc",36,"jdbc","JDBC","🔌","Как управлять транзакциями в JDBC","Транзакция в JDBC — это набор операций с базой данных, выполняемых как единое целое: либо все операции завершаются успешно (commit), либо все отменяются (rollback).\n\nПо умолчанию JDBC работает в режиме autoCommit = true, то есть каждый SQL-запрос автоматически коммитится. Для ручного управления транзакциями необходимо отключить автокоммит.\n\n### Базовое управление\n\n```java\nconnection.setAutoCommit(false); \u002F\u002F начинаем транзакцию\ntry {\n    \u002F\u002F выполняем SQL-операции\n    connection.commit();         \u002F\u002F подтверждаем\n} catch (SQLException e) {\n    connection.rollback();       \u002F\u002F откатываем при ошибке\n    throw e;\n} finally {\n    connection.setAutoCommit(true); \u002F\u002F восстанавливаем режим\n}\n```\n\n### Savepoint\n\nSavepoint позволяет создать промежуточную точку внутри транзакции, к которой можно откатиться без отката всей транзакции:\n\n```java\nSavepoint sp = connection.setSavepoint(\"before_notification\");\ntry {\n    \u002F\u002F дополнительная операция\n} catch (SQLException e) {\n    connection.rollback(sp); \u002F\u002F откат только до savepoint\n}\nconnection.commit(); \u002F\u002F основная операция сохраняется\n```\n\n### Сравнение с Spring @Transactional\n\n| Аспект | Чистый JDBC | Spring @Transactional |\n|:-------|:------------|:----------------------|\n| Управление соединением | Вручную | Автоматически |\n| Начало транзакции | setAutoCommit(false) | Декларативно через аннотацию |\n| Коммит | connection.commit() | Автоматически при успешном завершении |\n| Откат | connection.rollback() | Автоматически при RuntimeException |\n| Уровень изоляции | setTransactionIsolation() | @Transactional(isolation = ...) |\n| Propagation | Нет поддержки | Полная поддержка (REQUIRED, REQUIRES_NEW и т.д.) |\n\n\u003Cdetails>\n\u003Csummary>Полный пример: перевод денег между счетами\u003C\u002Fsummary>\n\n```java\npublic void transferMoney(Connection connection, long fromAccountId,\n                          long toAccountId, BigDecimal amount)\n        throws SQLException {\n    connection.setAutoCommit(false);\n\n    try {\n        \u002F\u002F Списание со счёта отправителя\n        try (PreparedStatement debit = connection.prepareStatement(\n                \"UPDATE accounts SET balance = balance - ? \"\n                + \"WHERE id = ? AND balance >= ?\")) {\n            debit.setBigDecimal(1, amount);\n            debit.setLong(2, fromAccountId);\n            debit.setBigDecimal(3, amount);\n            int updated = debit.executeUpdate();\n            if (updated == 0) {\n                throw new SQLException(\n                    \"Недостаточно средств на счёте \" + fromAccountId);\n            }\n        }\n\n        \u002F\u002F Зачисление на счёт получателя\n        try (PreparedStatement credit = connection.prepareStatement(\n                \"UPDATE accounts SET balance = balance + ? WHERE id = ?\")) {\n            credit.setBigDecimal(1, amount);\n            credit.setLong(2, toAccountId);\n            credit.executeUpdate();\n        }\n\n        connection.commit();\n    } catch (SQLException e) {\n        connection.rollback();\n        throw e;\n    } finally {\n        connection.setAutoCommit(true);\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Вспомогательный класс TransactionTemplate\u003C\u002Fsummary>\n\n```java\npublic class TransactionTemplate {\n\n    private final DataSource dataSource;\n\n    public TransactionTemplate(DataSource dataSource) {\n        this.dataSource = dataSource;\n    }\n\n    @FunctionalInterface\n    public interface TransactionCallback\u003CT> {\n        T execute(Connection connection) throws SQLException;\n    }\n\n    public \u003CT> T executeInTransaction(TransactionCallback\u003CT> callback) {\n        try (Connection conn = dataSource.getConnection()) {\n            conn.setAutoCommit(false);\n            try {\n                T result = callback.execute(conn);\n                conn.commit();\n                return result;\n            } catch (Exception e) {\n                conn.rollback();\n                throw new RuntimeException(\"Ошибка в транзакции\", e);\n            }\n        } catch (SQLException e) {\n            throw new RuntimeException(\"Ошибка подключения\", e);\n        }\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n### Важное\n\n- Всегда отключайте autoCommit перед началом транзакции\n- Используйте try-catch-finally для гарантированного rollback при ошибке\n- Закрывайте Connection после завершения работы с транзакцией\n- Уровень изоляции устанавливается через setTransactionIsolation() — выбирайте минимально необходимый\n\n### Частые ошибки\n\n- Забывать вызвать rollback() в блоке catch — данные могут остаться в неконсистентном состоянии\n- Не восстанавливать autoCommit после транзакции — последующие операции не будут коммититься\n- Держать транзакцию открытой слишком долго — блокирует записи в БД\n- Не закрывать PreparedStatement внутри транзакции — утечка ресурсов\n\n### Как используется в 2026\n\n- В большинстве проектов транзакции управляются через Spring @Transactional\n- Чистый JDBC для транзакций используется в микрофреймворках (Javalin, Spark) и библиотеках\n- Saga-паттерн для распределённых транзакций между микросервисами вместо XA\n- Virtual threads (Java 21+) упрощают написание транзакционного кода без callback-ов\n\n> **На собеседовании:** покажите паттерн setAutoCommit(false) -> try { ... commit() } catch { rollback() }. Упомяните Savepoint для частичного отката. Обязательно скажите, что в реальных проектах используется Spring @Transactional, а чистый JDBC — для понимания того, что происходит «под капотом». Частый follow-up: что такое propagation и почему его нет в чистом JDBC.","","middle",[15,7,16],"databases","transaction",[],null,{"title":20,"description":21,"ogTitle":20,"ogDescription":22,"keywords":23,"schemaAnswer":32,"featuredSnippetReady":33},"Управление транзакциями в JDBC -- Gymterview","Транзакции в JDBC: setAutoCommit(false), commit, rollback, Savepoint. Сравнение с Spring @Transactional: propagation, изоляция, декларативный подход.","Ручное управление транзакциями в JDBC: autoCommit, commit, rollback, Savepoint. Сравнение с Spring @Transactional.",[24,25,26,27,28,29,8,30,31],"транзакции","setAutoCommit","commit","rollback","Savepoint","@Transactional","Java","собеседование","Транзакция -- набор операций, выполняемых как единое целое. По умолчанию autoCommit=true. Для ручного управления: setAutoCommit(false), затем commit() при успехе или rollback() при ошибке. Savepoint позволяет частичный откат. В реальных проектах используется Spring @Transactional для декларативного управления.",true]