SQL Transactions
Transactions allow you to execute multiple SQL operations as a single atomic unit of work. They ensure data integrity by following the ACID principles (Atomicity, Consistency, Isolation, Durability).
Atomicity
All operations succeed or none do
Consistency
Database remains in a valid state
Isolation
Concurrent transactions don't interfere
Durability
Committed changes persist
Sample Tables for Examples
CREATE TABLE accounts (
account_id INT PRIMARY KEY,
account_name VARCHAR(100) NOT NULL,
balance DECIMAL(15,2) NOT NULL,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE transactions (
transaction_id INT PRIMARY KEY,
from_account INT,
to_account INT,
amount DECIMAL(15,2),
transaction_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(20) DEFAULT 'PENDING'
);
INSERT INTO accounts VALUES
(1001, 'Checking Account', 5000.00, CURRENT_TIMESTAMP),
(1002, 'Savings Account', 15000.00, CURRENT_TIMESTAMP),
(1003, 'Business Account', 25000.00, CURRENT_TIMESTAMP);
Basic Transaction Syntax
-- MySQL/PostgreSQL/SQLite
START TRANSACTION;
-- SQL statements
COMMIT;
-- or ROLLBACK;
-- SQL Server
BEGIN TRANSACTION;
-- SQL statements
COMMIT;
-- or ROLLBACK;
-- Oracle
SET TRANSACTION;
-- SQL statements
COMMIT;
-- or ROLLBACK;
Transaction Example: Money Transfer
START TRANSACTION;
-- Deduct from source account
UPDATE accounts
SET balance = balance - 1000
WHERE account_id = 1001;
-- Add to destination account
UPDATE accounts
SET balance = balance + 1000
WHERE account_id = 1002;
-- Record the transaction
INSERT INTO transactions (transaction_id, from_account, to_account, amount)
VALUES (1, 1001, 1002, 1000);
-- Only commit if all operations succeed
COMMIT;
-- If any error occurs:
-- ROLLBACK;
Savepoints
Create markers within a transaction to roll back to:
START TRANSACTION;
-- Initial operations
UPDATE accounts SET balance = balance - 500 WHERE account_id = 1001;
SAVEPOINT after_withdrawal;
-- More operations
UPDATE accounts SET balance = balance + 500 WHERE account_id = 1003;
SAVEPOINT after_deposit;
-- Conditionally rollback to savepoint
-- ROLLBACK TO after_withdrawal;
COMMIT;
Transaction Isolation Levels
Control how transactions interact with each other:
Level | Description | Concurrency Issues |
---|---|---|
READ UNCOMMITTED | See uncommitted changes | Dirty reads, non-repeatable reads, phantom reads |
READ COMMITTED | See only committed changes | Non-repeatable reads, phantom reads |
REPEATABLE READ | Consistent reads within transaction | Phantom reads |
SERIALIZABLE | Complete isolation | None (but lowest performance) |
Setting Isolation Level
-- MySQL
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- SQL Server
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- PostgreSQL
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Common Transaction Patterns
Retry Logic
-- Pseudocode for transaction with retry
DECLARE retry_count INT DEFAULT 0;
DECLARE success BOOLEAN DEFAULT FALSE;
WHILE retry_count < 3 AND NOT success DO
BEGIN
START TRANSACTION;
-- Transaction logic
COMMIT;
SET success = TRUE;
EXCEPTION
WHEN deadlock_detected THEN
ROLLBACK;
SET retry_count = retry_count + 1;
-- Optional: add delay
END;
END WHILE;
Nested Transactions
-- Using savepoints to simulate nested transactions
START TRANSACTION;
-- Outer transaction
UPDATE accounts SET balance = balance - 200 WHERE account_id = 1001;
SAVEPOINT nested_transaction;
-- Inner transaction
UPDATE accounts SET balance = balance + 200 WHERE account_id = 1002;
-- Conditionally commit/rollback inner
-- RELEASE SAVEPOINT nested_transaction; -- "commit"
-- or ROLLBACK TO nested_transaction; -- "rollback"
COMMIT; -- Commits the outer transaction
Distributed Transactions
Transactions spanning multiple databases:
-- MySQL (XA Transactions)
XA START 'transfer_transaction';
UPDATE db1.accounts SET balance = balance - 500 WHERE account_id = 1001;
UPDATE db2.accounts SET balance = balance + 500 WHERE account_id = 2001;
XA END 'transfer_transaction';
XA PREPARE 'transfer_transaction';
XA COMMIT 'transfer_transaction';
-- On error:
-- XA ROLLBACK 'transfer_transaction';
Transaction Best Practices
- Keep transactions as short as possible
- Handle exceptions properly with rollback
- Choose the right isolation level for your needs
- Avoid user interaction within transactions
- Consider using optimistic/pessimistic locking as needed
- Monitor for long-running transactions
Common Transaction Issues
Issue | Description | Solution |
---|---|---|
Deadlock | Two transactions waiting for each other | Retry logic, proper indexing |
Long-running | Transaction holding locks too long | Break into smaller transactions |
Dirty read | Reading uncommitted changes | Higher isolation level |
Phantom read | New rows appearing in subsequent reads | SERIALIZABLE isolation |
Transaction Lifecycle
START → [Operations] → (Success) → COMMIT
START → [Operations] → (Failure) → ROLLBACK