Ответ
Транзакция — это атомарная последовательность операций с базой данных, которая либо выполняется полностью (commit), либо полностью откатывается (rollback) при ошибке. В Node.js работа с транзакциями зависит от используемой базы данных и драйвера/ORM.
Реализация транзакций с PostgreSQL через node-postgres:
const { Client } = require('pg');
const client = new Client();
await client.connect();
// Начало транзакции
await client.query('BEGIN');
try {
// Операция 1: Создание пользователя
await client.query(
'INSERT INTO users(name, email) VALUES($1, $2) RETURNING id',
['John Doe', 'john@example.com']
);
// Операция 2: Создание заказа для пользователя
const result = await client.query(
'INSERT INTO orders(user_id, amount) VALUES($1, $2) RETURNING id',
[1, 100.50]
);
// Фиксация транзакции
await client.query('COMMIT');
console.log('Transaction committed, order ID:', result.rows[0].id);
} catch (error) {
// Откат при любой ошибке
await client.query('ROLLBACK');
console.error('Transaction rolled back:', error.message);
throw error;
} finally {
await client.end();
}
Реализация через Sequelize ORM:
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password');
const transaction = await sequelize.transaction({
isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED
});
try {
// Создание пользователя в транзакции
const user = await User.create({
name: 'Alice',
email: 'alice@example.com'
}, { transaction });
// Создание связанной записи
await Order.create({
userId: user.id,
total: 250.75,
status: 'pending'
}, { transaction });
// Фиксация
await transaction.commit();
} catch (error) {
// Автоматический откат
await transaction.rollback();
console.error('Transaction failed:', error);
}
Свойства ACID в контексте Node.js:
-
Атомарность (Atomicity):
// Либо обе операции выполнятся, либо ни одной await transferFunds(senderId, receiverId, amount); -
Согласованность (Consistency):
// Транзакция гарантирует соблюдение constraints // FOREIGN KEY, CHECK, NOT NULL и т.д. -
Изолированность (Isolation):
// Уровни изоляции в PostgreSQL через Node.js const levels = { READ_UNCOMMITTED: 'READ UNCOMMITTED', READ_COMMITTED: 'READ COMMITTED', // По умолчанию REPEATABLE_READ: 'REPEATABLE READ', SERIALIZABLE: 'SERIALIZABLE' }; -
Долговечность (Durability):
// После COMMIT данные гарантированно сохраняются // даже при сбое системы (WAL - Write Ahead Logging)
Практические сценарии использования в Node.js:
- Финансовые операции (переводы между счетами)
- Создание заказов с несколькими позициями
- Обновление инвентаря при покупке
- Миграции данных с сохранением целостности
Ответ 18+ 🔞
Слушай, давай разберем эту тему про транзакции, а то у некоторых от одного слова «ACID» уже волнение ебать начинается, как будто в химической лаборатории очутились.
Представь себе, что транзакция — это как поход в магазин за пивом и чипсами. Ты либо покупаешь всё вместе и идешь домой с полным пакетом (это COMMIT), либо, если на кассе карта ляжет или денег не хватит, ты нихуя не покупаешь и уходишь с пустыми руками (это ROLLBACK). Получить только пиво, а чипсы забыть — это не наш метод. Всё или ничего, атомарно, блядь.
Вот смотри, как это на коленке через node-postgres делается. Главное — начать и не забыть в конце прибраться, а то соединение висеть будет.
const { Client } = require('pg');
const client = new Client();
await client.connect();
// Начинаем наш маленький финансовый триллер
await client.query('BEGIN');
try {
// Операция 1: Создание пользователя
await client.query(
'INSERT INTO users(name, email) VALUES($1, $2) RETURNING id',
['John Doe', 'john@example.com']
);
// Операция 2: Создание заказа для пользователя
const result = await client.query(
'INSERT INTO orders(user_id, amount) VALUES($1, $2) RETURNING id',
[1, 100.50]
);
// Если дошли сюда без косяков — фиксируем, красавчики
await client.query('COMMIT');
console.log('Transaction committed, order ID:', result.rows[0].id);
} catch (error) {
// А тут что-то пошло не так... Откатываем всё к хуям собачьим!
await client.query('ROLLBACK');
console.error('Transaction rolled back:', error.message);
throw error;
} finally {
// И в любом случае соединение закрываем, а то ресурсы жрёт
await client.end();
}
А если ты любитель ORM и высоких абстракций, то в Sequelize это выглядит поприличнее, но суть та же — обёртка, которая за тебя BEGIN, COMMIT и ROLLBACK сама напишет.
const transaction = await sequelize.transaction({
isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED
});
try {
const user = await User.create({
name: 'Alice',
email: 'alice@example.com'
}, { transaction });
await Order.create({
userId: user.id,
total: 250.75,
status: 'pending'
}, { transaction });
// Всё гуд, зафиксировали
await transaction.commit();
} catch (error) {
// Пиздец, ошибка — откатываем как будто ничего и не было
await transaction.rollback();
console.error('Transaction failed:', error);
}
Теперь про эти ваши ACID, а то без них никуда. Это, блядь, как четыре кита, на которых держится доверие к базе.
-
Атомарность (Atomicity) — это про «пан или пропал». Как в том примере выше: либо юзер и заказ создались, либо нихуя. Никаких промежуточных состояний, где юзер есть, а заказа нет. Это пиздец как важно для денежных переводов, представляешь?
-
Согласованность (Consistency) — база следит, чтобы ты не накосячил. Если есть внешние ключи,
NOT NULLили проверки — транзакция либо пройдёт все эти правила, либо отвалится. Нельзя заказать 100500 единиц товара, которых на складе 10. База тебе: «Ну-ну, чувак, давай по-новой». -
Изолированность (Isolation) — вот тут веселье начинается. Представь, что два скрипта одновременно лезут в одни и те же данные. Чтобы они друг другу не насрали в тарелку, есть уровни изоляции. От «читай что хочешь, даже неподтверждённые данные» до полной паранойи
SERIALIZABLE, где всё выполняется так, будто происходит строго по очереди, даже если работает овердохуища потоков. В Постгресе по умолчаниюREAD COMMITTED— нормальный такой, адекватный вариант. -
Долговечность (Durability) — это когда после
COMMIT'а можешь хоть рубильник дернуть. Данные уже в надёжном журнале (WAL), и после перезагрузки они на месте будут. Не как в оперативке — чихнул, и всё пропало.
Где это всё в ноде юзать? Да везде, где важен порядок и целостность:
- Перевод бабла со счёта на счёт. Списали у одного — зачислили другому. Иначе будет срака, а не финансы.
- Оформление заказа в интернет-магазине: резервируем товары на складе, создаём запись заказа, списываем деньги. Если на любом этапе облом — откатываем всю цепочку, чтобы товар не потерялся в небытии.
- Сложные миграции данных, когда нужно переложить кучу записей из одной таблицы в другую, обновив кучу связей.
Короче, транзакции — это твой главный инструмент против хаоса и бардака в данных. Без них писать что-то серьёзное — это как строить дом на песке во время урагана. Обязательно накроется медным тазом.
Видео-ответы
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶