🗄️SQL Templates

Transaction Control (BEGIN, COMMIT, ROLLBACK)

Manage database transactions for data consistency and error handling

Explanation

Transactions ensure all-or-nothing execution of multiple SQL statements for data integrity.

Examples

Basic transaction
Input
BEGIN; UPDATE...; COMMIT;
Output
Changes saved atomically
Rollback on error
Input
BEGIN; ...; ROLLBACK;
Output
Changes reverted

Code Examples

SQL
-- Basic transaction
BEGIN;

UPDATE accounts 
SET balance = balance - 100 
WHERE id = 1;

UPDATE accounts 
SET balance = balance + 100 
WHERE id = 2;

COMMIT;

-- Transaction with rollback on error
BEGIN;

UPDATE inventory 
SET quantity = quantity - 5 
WHERE product_id = 123;

INSERT INTO orders (user_id, product_id, quantity)
VALUES (1, 123, 5);

-- If any error occurs, rollback
ROLLBACK;

-- Transaction with conditional logic
BEGIN;

-- Check if sufficient balance
SELECT balance INTO @current_balance
FROM accounts 
WHERE id = 1;

IF @current_balance >= 100 THEN
  UPDATE accounts 
  SET balance = balance - 100 
  WHERE id = 1;
  
  INSERT INTO transactions (account_id, amount, type)
  VALUES (1, -100, 'withdrawal');
  
  COMMIT;
ELSE
  ROLLBACK;
END IF;

-- Savepoint (partial rollback)
BEGIN;

INSERT INTO orders (user_id, total) 
VALUES (1, 100);

SAVEPOINT order_created;

INSERT INTO order_items (order_id, product_id, quantity)
VALUES (LAST_INSERT_ID(), 123, 2);

-- If this fails, can rollback to savepoint
ROLLBACK TO SAVEPOINT order_created;

-- Or continue and commit everything
COMMIT;

-- Transaction isolation levels
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
-- queries...
COMMIT;

-- Isolation levels:
-- READ UNCOMMITTED - can see uncommitted changes (dirty reads)
-- READ COMMITTED - only see committed changes (default)
-- REPEATABLE READ - consistent snapshot during transaction
-- SERIALIZABLE - full isolation, as if transactions run serially
JavaScript/Node.js
// Node.js with pg (PostgreSQL)
const { Client } = require('pg');
const client = new Client();

async function transferMoney(fromId, toId, amount) {
  try {
    await client.query('BEGIN');
    
    // Deduct from sender
    await client.query(
      'UPDATE accounts SET balance = balance - $1 WHERE id = $2',
      [amount, fromId]
    );
    
    // Add to receiver
    await client.query(
      'UPDATE accounts SET balance = balance + $1 WHERE id = $2',
      [amount, toId]
    );
    
    await client.query('COMMIT');
    console.log('Transfer successful');
  } catch (error) {
    await client.query('ROLLBACK');
    console.error('Transfer failed, rolled back:', error);
    throw error;
  }
}

// With connection pooling
async function safeUpdate(pool) {
  const client = await pool.connect();
  
  try {
    await client.query('BEGIN');
    
    // Multiple queries...
    await client.query('UPDATE ...');
    await client.query('INSERT ...');
    
    await client.query('COMMIT');
  } catch (e) {
    await client.query('ROLLBACK');
    throw e;
  } finally {
    client.release();
  }
}

💡 Tips

  • Use transactions for related updates
  • Always handle errors and ROLLBACK
  • Keep transactions short to avoid locks
  • Use appropriate isolation level
  • SAVEPOINT for partial rollback
  • Transactions are automatic in some ORMs
  • Test transaction logic thoroughly

⚠️ Common Pitfalls

  • Forgetting COMMIT leaves transaction open
  • Long transactions lock tables
  • Deadlocks with concurrent transactions
  • DDL statements auto-commit in some DBs
  • Network errors can leave transactions hanging
  • Wrong isolation level causes data issues