** Building a Reliable Digital Wallet System (Like PhonePe / GPay)**
Introduction
In today’s digital world, applications like Google Pay, PhonePe, and Paytm handle millions of financial transactions every second.
Behind these simple “Pay” buttons lies a highly critical system where data consistency is everything. Even a tiny inconsistency can lead to:
•Money loss
• Duplicate transactions
• Incorrect balances
To prevent this, databases rely on ACID properties, especially Isolation, which ensures transactions don’t interfere with each other in unsafe ways.
Database Setup
We begin with a simple accounts table:
CREATE TABLE accounts (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
balance INT NOT NULL CHECK (balance >= 0),
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Sample Data
INSERT INTO accounts (name, balance)
VALUES
('Alice', 1000),
('Bob', 500);
This simulates a wallet system where users hold balances.
Simulating Concurrent Transactions
To understand how isolation works, we simulate two concurrent database sessions.
Scenario: Two Transactions on Same Account
Session 1 (T1)
`BEGIN;
UPDATE accounts
SET balance = balance - 800
WHERE name = 'Alice';`
Alice’s balance becomes 200 (but uncommitted)
Session 2 (T2)
`BEGIN;
SELECT balance FROM accounts WHERE name = 'Alice'; `
Now the key question:
Can T2 see the updated balance (200)? Or still 1000?
This depends on the isolation level.
Isolation Levels Explained
Read Uncommitted
Lowest isolation (rarely used in PostgreSQL)
•T2 can see uncommitted data
•Leads to Dirty Reads
Problem
T2 might see balance = 200 even if T1 later rolls back.
Result: Incorrect financial state
Read Committed (Default in PostgreSQL)**
•T2 cannot see uncommitted changes
•Only committed data is visible
✔ Behavior
T2 sees:
Alice = 1000
Issue: Non-repeatable Reads
If T1 commits later, T2 may see different values in the same transaction.
Repeatable Read
•Ensures consistent snapshot during transaction
✔ Behavior
•T2 always sees 1000 during its transaction
•Even if T1 commits later
Issue: Phantom reads still possible (in some DBs)
Serialize (Highest Isolation)
Most strict and safest
•Transactions behave as if executed one after another
✔ Behavior
•Prevents:
•Dirty reads
•Non-repeatable reads
•Lost updates
Example Outcome
One transaction may fail with:
ERROR: could not serialize access due to concurrent update
You must retry the transaction
Key Problems Demonstrated
Dirty Read
Reading uncommitted data → leads to wrong balance
Non-Repeatable Read
Same query returns different results within a transaction
Lost Update
`-- T1 reads 1000
-- T2 reads 1000
-- T1 updates to 200
-- T2 updates to 300
-- Final = 300 (T1 lost) `
Two transactions overwrite each other’s updates
Example:
Why Isolation Matters in Wallet Systems
In a real-world wallet:
•Multiple users may send money simultaneously
•Systems must prevent:
•Double spending
•Balance corruption
•Race conditions
Without isolation, financial systems would be unreliable.
Best Practices for Wallet Systems
SELECT * FROM accounts
WHERE name = 'Alice'
FOR UPDATE;
•Use Serializable isolation for critical transactions
•Use row-level locking:
Implement retry logic for failed transactions
•Keep transactions short and efficient
Conclusion
Building a digital wallet system is not just about transferring money—it’s about guaranteeing correctness under concurrency.
Through this experiment, we observed how different isolation levels impact:
•Data visibility
•Transaction safety
•System reliability
Top comments (0)