0
0
Node.jsframework~5 mins

Transaction handling in Node.js

Choose your learning style9 modes available
Introduction

Transaction handling helps keep your data safe by making sure a group of actions all succeed or all fail together.

When saving multiple related pieces of data that must all be correct together, like an order and its items.
When updating several tables in a database and you want to avoid partial changes.
When transferring money between accounts to prevent losing or creating money by mistake.
When you want to undo all changes if any step in a process fails.
When working with databases that support transactions to keep data consistent.
Syntax
Node.js
async function doTransaction() {
  const client = await pool.connect();
  try {
    await client.query('BEGIN');
    // your queries here
    await client.query('COMMIT');
  } catch (e) {
    await client.query('ROLLBACK');
    throw e;
  } finally {
    client.release();
  }
}

Use BEGIN to start a transaction, COMMIT to save changes, and ROLLBACK to undo if something goes wrong.

Always release the database client after finishing to avoid connection leaks.

Examples
Start a transaction, insert a user, then save the change.
Node.js
await client.query('BEGIN');
await client.query('INSERT INTO users(name) VALUES($1)', ['Alice']);
await client.query('COMMIT');
Transfer money between accounts safely by updating both balances inside a transaction.
Node.js
try {
  await client.query('BEGIN');
  await client.query('UPDATE accounts SET balance = balance - 100 WHERE id = $1', [fromId]);
  await client.query('UPDATE accounts SET balance = balance + 100 WHERE id = $1', [toId]);
  await client.query('COMMIT');
} catch (e) {
  await client.query('ROLLBACK');
  throw e;
}
Sample Program

This program safely transfers money between two accounts. It checks the balance, updates both accounts, and uses a transaction to keep data correct.

Node.js
import pkg from 'pg';
const { Pool } = pkg;

const pool = new Pool({
  user: 'user',
  host: 'localhost',
  database: 'testdb',
  password: 'password',
  port: 5432,
});

async function transferMoney(fromId, toId, amount) {
  const client = await pool.connect();
  try {
    await client.query('BEGIN');
    const res1 = await client.query('SELECT balance FROM accounts WHERE id = $1', [fromId]);
    if (res1.rows.length === 0) throw new Error('From account not found');
    if (res1.rows[0].balance < amount) throw new Error('Insufficient funds');

    await client.query('UPDATE accounts SET balance = balance - $1 WHERE id = $2', [amount, fromId]);
    await client.query('UPDATE accounts SET balance = balance + $1 WHERE id = $2', [amount, toId]);

    await client.query('COMMIT');
    console.log('Transfer completed');
  } catch (e) {
    await client.query('ROLLBACK');
    console.error('Transfer failed:', e.message);
  } finally {
    client.release();
  }
}

// Example usage
transferMoney(1, 2, 50);
OutputSuccess
Important Notes

Always handle errors to rollback transactions and avoid corrupt data.

Transactions can lock rows, so keep them short to avoid slowing down other users.

Not all databases support transactions the same way; check your database docs.

Summary

Transactions group multiple database actions to succeed or fail together.

Use BEGIN, COMMIT, and ROLLBACK commands to control transactions.

Always release database connections and handle errors carefully.