SQL Practice Logo

SQLPractice Online

Transaction Control (ACID): Examples

Module: Data Modification & Transactions

Money Transfer with Error Handling and Balance Validation

advanced

Bank needs to transfer $500 from Account A to Account B. Requirements: (1) Debit and credit must both succeed (atomicity), (2) Source account balance must stay ≥ 0 (consistency), (3) Concurrent transfers must not interfere (isolation), (4) Committed transfer must survive crashes (durability). Traditional approach: Separate UPDATE statements without transaction. Problem: Debit succeeds but credit fails (money disappears), or concurrent transfers cause negative balance. Solution: Use transaction with error handling and balance validation.

-- PostgreSQL money transfer with error handling

CREATE OR REPLACE FUNCTION transfer_money(

from_account_id VARCHAR(10),

to_account_id VARCHAR(10),

transfer_amount DECIMAL(10,2)

) RETURNS TEXT AS $$

DECLARE

from_balance DECIMAL(10,2);

to_balance DECIMAL(10,2);

BEGIN

-- Start transaction (implicit in function)

-- Step 1: Lock source account and check balance

SELECT balance INTO from_balance

FROM accounts

WHERE account_id = from_account_id

FOR UPDATE; -- Lock row to prevent concurrent updates

IF NOT FOUND THEN

RAISE EXCEPTION 'Source account % not found', from_account_id;

END IF;

IF from_balance < transfer_amount THEN

RAISE EXCEPTION 'Insufficient funds: balance=%, amount=%', from_balance, transfer_amount;

END IF;

-- Step 2: Lock destination account

SELECT balance INTO to_balance

FROM accounts

WHERE account_id = to_account_id

FOR UPDATE; -- Lock row

IF NOT FOUND THEN

RAISE EXCEPTION 'Destination account % not found', to_account_id;

END IF;

-- Step 3: Debit source account

UPDATE accounts

SET balance = balance - transfer_amount,

updated_at = CURRENT_TIMESTAMP

WHERE account_id = from_account_id;

-- Step 4: Credit destination account

UPDATE accounts