Database Transactions
One thing you don't want in a wallet system is money leaving one account without reaching the other.
I am building PropInvest, a property investment platform where users can fund wallets and invest in real estate. When an investor puts money into a property, the system needs to:
- Deduct funds from their wallet
- Create the investment record
- Update the property's funding status
- Log the transaction
Now, what happens if the wallet is debited, but the server crashes before creating the investment?
The investor's money is gone, but they don't own any shares. That's a nightmare.
This is why database transactions matter.
A database transaction lets you group multiple operations together so they either all succeed or all fail.
If the wallet debit, investment creation, and transaction log all succeed, the transaction commits.
If any step fails, everything rolls back. The wallet stays untouched. No partial state.
This is called atomicity, the A in ACID.
ACID stands for:
- Atomicity: All operations succeed, or none do.
- Consistency: The transaction preserves database rules and constraints.
- Isolation: Concurrent transactions don't interfere with each other.
- Durability: Once committed, changes persist even if the system crashes.
For PropVest's wallet operations, every debit, credit, and record is wrapped in the same database transaction.
One important detail though: this protects database changes within that transaction. It doesn't automatically reverse an external action, like a payment already sent to Paystack.
That is why I also used idempotency keys, locked balances, and reconciliation workers. But transactions were the foundation.
When handling money, a successful API response isn't enough. You need to make sure the underlying operations are actually safe.
Never assume your code will complete every step. Design your database operations to handle failure.