Ответ
Управление транзакциями в Java осуществляется через JDBC, JPA/Hibernate или Spring @Transactional. Ключевые принципы: атомарность, согласованность, изоляция, долговечность (ACID).
1. JDBC (низкоуровневый API)
Connection conn = dataSource.getConnection();
try {
conn.setAutoCommit(false); // Начало транзакции
PreparedStatement stmt = conn.prepareStatement(
"UPDATE accounts SET balance = ? WHERE id = ?"
);
stmt.setBigDecimal(1, newBalance);
stmt.setLong(2, accountId);
stmt.executeUpdate();
conn.commit(); // Фиксация изменений
} catch (SQLException e) {
conn.rollback(); // Откат при ошибке
throw e;
} finally {
conn.setAutoCommit(true);
conn.close();
}
2. JPA/Hibernate
EntityTransaction tx = entityManager.getTransaction();
try {
tx.begin();
Account account = entityManager.find(Account.class, accountId);
account.setBalance(newBalance);
tx.commit();
} catch (Exception e) {
if (tx.isActive()) {
tx.rollback(); // Явный откат
}
throw e;
}
3. Spring @Transactional (рекомендуемый подход)
@Service
public class AccountService {
@Transactional(isolation = Isolation.READ_COMMITTED,
rollbackFor = {SQLException.class})
public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
// Бизнес-логика
// При исключении — автоматический rollback
}
}
Ключевые аспекты:
- Уровни изоляции:
READ_UNCOMMITTED,READ_COMMITTED,REPEATABLE_READ,SERIALIZABLE. - Распространённые проблемы: грязное чтение, неповторяемое чтение, фантомное чтение.
- Паттерны: оптимистичные/пессимистичные блокировки, компенсирующие транзакции (Saga).
Ответ 18+ 🔞
А, ну это же про транзакции, ёпта! Ну, классика жанра, блядь. Все эти ACID-ы, которые в рот меня чих-пых, пока на проде гоняешь. Слушай, давай разжую, как есть, без этой охуевшей академической пыли.
Первое, JDBC — это как голыми руками в говне ковыряться, блядь. Низкоуровневое такое, ручное управление. Весь этот цирк с setAutoCommit(false), commit() и rollback(). Один косяк — и всё, приехали, сидишь и думаешь, какого хуя данные не обновились, а они просто в транзакции висят, сука.
Connection conn = dataSource.getConnection();
try {
conn.setAutoCommit(false); // Всё, понеслась, блядь!
PreparedStatement stmt = conn.prepareStatement(
"UPDATE accounts SET balance = ? WHERE id = ?"
);
stmt.setBigDecimal(1, newBalance);
stmt.setLong(2, accountId);
stmt.executeUpdate();
conn.commit(); // Уфф, зафиксировали, живём!
} catch (SQLException e) {
conn.rollback(); // Всё нахуй, откатываем! Пиздец, ошибка!
throw e;
} finally {
conn.setAutoCommit(true);
conn.close(); // Не забудь закрыть, а то коннектов дохуя сожрёшь!
}
Работает, конечно, но писать это каждый раз — терпения ебать ноль. Один finally забыл — и у тебя утечка, привет.
Дальше, JPA/Hibernate — уже получше, но тоже своя банда. Тут уже EntityTransaction. Начинаешь (begin()), делаешь дела, фиксируешь (commit()). Словил исключение — rollback(), если транзакция ещё жива. Главное — не проёбывайся с проверкой isActive(), а то получишь ещё один пиздец поверх первого.
EntityTransaction tx = entityManager.getTransaction();
try {
tx.begin();
Account account = entityManager.find(Account.class, accountId);
account.setBalance(newBalance);
tx.commit(); // Вроде ок!
} catch (Exception e) {
if (tx.isActive()) {
tx.rollback(); // Ага, ловим и откатываем, хитрая жопа!
}
throw e;
}
Уже симпатичнее, но всё равно рутина, блядь. Весь этот try-catch — у меня волнение ебать от одного вида.
И наконец, Spring @Transactional — это просто песня, ёбана! Аннотацию кинул — и всё, блядь. Фреймворк сам обернёт твой метод в транзакцию, сам закоммитит, сам откатит при косяке. Красота, да и только!
@Service
public class AccountService {
@Transactional(isolation = Isolation.READ_COMMITTED,
rollbackFor = {SQLException.class})
public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
// Делай что хочешь тут
// Кинется исключение — всё само откатится, как по маслу!
}
}
Вот это я понимаю — элегантно, сука. Нехуй мозги парить.
А теперь про подводные ебучки, которые всех накрывают медным тазом:
- Уровни изоляции. Это пиздец, чувак.
READ_UNCOMMITTED— это когда читаешь даже неподтверждённые данные, как будто подглядываешь в замочную скважину.READ_COMMITTED— уже норм, только коммитнутое видишь.REPEATABLE_READиSERIALIZABLE— это когда всё серьёзно, но и тормозят соответственно, овердохуища. - Проблемы. Грязное чтение, неповторяемое чтение, фантомы... Это не про духов, а про то, как данные у тебя из-под носа уплывают, если изоляцию криво настроил. Чувствуешь подозрение, блядь? Вот-вот.
- Паттерны. Оптимистичная блокировка — это как надеяться, что никто твою запись не тронет (версию проверяешь). Пессимистичная — это сразу захватываешь лок, как будто говоришь: «Отойди, сука, это моё!». А Saga — это для распределённых систем, когда одна большая транзакция разбивается на кучу маленьких с компенсациями, если что-то пошло не так. Сложна, блядь, но жить можно.
Короче, суть в чём: не выёбывайся, используй @Transactional от Spring, если можешь. И думай головой, какой уровень изоляции тебе нужен, а то потом будешь искать, куда делись твои данные, а они, блядь, фантомом прочитались и испарились. В рот меня чих-пых!