Phantom Read in Database Transactions

Interactive Demo: Understanding Transaction Isolation Problems

👻 What is Phantom Read?

Phantom Read: When a transaction re-executes a query and finds new rows that didn't exist during the first execution, inserted by another concurrent transaction.

🥭 Mango Pickle Order Scenario

📊
Transaction 1: Count orders WHERE product = 'Mango Pickle' → Result: 5
Transaction 2: INSERT new 'Mango Pickle' order → COMMIT
👻
Transaction 1: Same count query → Result: 6 (Phantom Row!)
Problem: Inconsistent results within same transaction
Click above buttons to explore Phantom Read phenomenon!

⚡ Live Transaction Simulator

Simulate: Watch phantom reads happen in real-time with concurrent transactions

🔍 Transaction 1 (Reader)

Status: Ready to start

➕ Transaction 2 (Writer)

Status: Waiting for Transaction 1

🔒 Transaction Isolation Levels & Phantom Read

Isolation Level Dirty Read Non-Repeatable Read Phantom Read Performance Use Case
READ UNCOMMITTED ❌ Possible ❌ Possible ❌ Possible 🚀 Fastest Analytics, Reporting
READ COMMITTED ✅ Prevented ❌ Possible ❌ Possible ⚡ Fast Most web applications
REPEATABLE READ ✅ Prevented ✅ Prevented ❌ Possible 🐌 Slower Financial calculations
SERIALIZABLE ✅ Prevented ✅ Prevented ✅ Prevented 🐢 Slowest Critical transactions

💻 SQL Code Examples

-- 👻 Phantom Read Demonstration
-- Transaction 1 (Connection 1)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN TRANSACTION;
-- First count query
SELECT COUNT(*) FROM Orders WHERE Product = 'Mango Pickle';
-- Result: 5 orders
-- ... doing other work ...
WAITFOR DELAY '00:00:05'; -- Wait 5 seconds
-- Meanwhile, Transaction 2 inserts and commits!
-- Second count query (same as first)
SELECT COUNT(*) FROM Orders WHERE Product = 'Mango Pickle';
-- Result: 6 orders (Phantom Read!)
COMMIT;
-- Transaction 2 (Connection 2) - Runs concurrently
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN TRANSACTION;
-- Insert new order while Transaction 1 is running
INSERT INTO Orders (Product, Quantity, Customer)
VALUES ('Mango Pickle', 2, 'Babita Ji');
COMMIT; -- This creates the phantom row
-- 🛡️ SERIALIZABLE Solution - Prevents Phantom Reads
-- Transaction 1 with SERIALIZABLE isolation
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
-- First count query - locks the range
SELECT COUNT(*) FROM Orders WHERE Product = 'Mango Pickle';
-- Result: 5 orders
-- Range lock prevents new inserts matching the condition
-- ... doing other work ...
WAITFOR DELAY '00:00:05';
-- Second count query
SELECT COUNT(*) FROM Orders WHERE Product = 'Mango Pickle';
-- Result: 5 orders (Consistent!)
COMMIT;
-- Now Transaction 2 can proceed
-- Transaction 2 - Will be blocked until Transaction 1 commits
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
-- This INSERT will be blocked by Transaction 1's range lock
INSERT INTO Orders (Product, Quantity, Customer)
VALUES ('Mango Pickle', 2, 'Babita Ji');
-- Waits until Transaction 1 completes
COMMIT;
✅ Benefits of SERIALIZABLE:
  • Prevents all concurrency phenomena (dirty read, non-repeatable read, phantom read)
  • Ensures consistent results within a transaction
  • Range locks prevent phantom rows
⚠️ Trade-offs:
  • Reduced concurrency (transactions may wait)
  • Higher chance of deadlocks
  • Lower performance
-- 🌍 Real World Example: E-commerce Inventory Management
-- Scenario: Checking low-stock items for reorder
-- Transaction 1: Daily inventory check
BEGIN TRANSACTION;
-- Find all low-stock items (< 10 units)
SELECT ProductID, ProductName, Stock
FROM Inventory
WHERE Stock < 10;
-- Result: 3 products need reordering
-- Calculate total reorder cost
SELECT SUM(ReorderCost) as TotalCost
FROM Inventory
WHERE Stock < 10;
-- Result: $1,500
-- ... manager reviews the list ...
-- Re-run the same queries for final confirmation
SELECT COUNT(*) FROM Inventory WHERE Stock < 10;
-- Without SERIALIZABLE: Could show 4 products (Phantom!)
-- With SERIALIZABLE: Shows 3 products (Consistent)
COMMIT;
-- Transaction 2: Concurrent sale reduces stock
BEGIN TRANSACTION;
-- Customer purchases last units of a product
UPDATE Inventory
SET Stock = Stock - 5
WHERE ProductID = 'WIDGET-123';
-- This brings stock from 12 to 7 (now < 10!)
COMMIT;
-- Creates a phantom row for Transaction 1's queries
🎯 Business Impact:
  • Without SERIALIZABLE: Inventory report shows inconsistent data, wrong reorder amounts
  • With SERIALIZABLE: Consistent snapshot of inventory throughout the transaction
  • Use Case: Financial reports, audit trails, inventory management

💡 Best Practices for Handling Phantom Reads

✅ Do This

  • Use SERIALIZABLE for critical financial operations
  • Choose appropriate isolation level based on consistency needs
  • Consider application-level consistency checks
  • Use optimistic locking for better performance
  • Test your application with concurrent load

❌ Avoid This

  • Using READ UNCOMMITTED for financial data
  • Ignoring phantom reads in reporting systems
  • Always using SERIALIZABLE (performance impact)
  • Not handling isolation level exceptions
  • Mixing different isolation levels carelessly