ACID Transactions
Understanding ACID is essential for choosing between SQL and NoSQL databases. Financial systems require ACID. Social media feeds may not.
The Core Idea
ACID stands for Atomicity (all or nothing), Consistency (data always valid), Isolation (concurrent transactions do not interfere), and Durability (committed data survives crashes). ACID guarantees are what make relational databases reliable for critical data like financial transactions.
Step-by-Step Walkthrough
When you execute a SQL transaction:
- BEGIN: Start transaction, allocate resources.
- Execute statements: Read/write data, buffer changes.
- COMMIT: Write all changes to the write-ahead log, flush to disk, release locks.
- If any step fails: ROLLBACK — undo all changes.
The WAL (Write-Ahead Log) is key to durability: changes are written to the log before being applied to data files. If the server crashes mid-transaction, the WAL can replay committed changes.
Why This Approach Wins
- Atomicity: A transaction either completes entirely or not at all. If transferring $100 fails midway, both accounts remain unchanged.
- Consistency: Data always satisfies constraints (foreign keys, unique constraints, check constraints). Invalid data is rejected.
- Isolation levels: Read Uncommitted, Read Committed, Repeatable Read, Serializable — each offers different tradeoffs between correctness and performance.
- Durability: Once a transaction is committed, it persists even if the server crashes. Achieved via write-ahead logs (WAL) and fsync.
- 2PC (Two-Phase Commit): Extends ACID across multiple databases. Coordinator asks all participants to prepare, then commit. Slow but correct.
In Production
PostgreSQL provides full ACID compliance with MVCC (Multi-Version Concurrency Control) for high-performance isolation.
Google Spanner extends ACID across global distributed databases using TrueTime for ordering.
MongoDB added multi-document ACID transactions in version 4.0, bridging the gap with relational databases.
Tradeoffs and Limitations
- ACID vs Performance: Stricter isolation = slower transactions. Serializable is the safest but slowest.
- ACID vs Scalability: Distributed ACID (2PC) is expensive. Many NoSQL databases trade ACID for horizontal scalability.
- Consistency vs Availability: In distributed databases, strict ACID often means CP (sacrificing availability during partitions).
Production Gotchas
- Assuming all databases provide ACID — many NoSQL databases provide weaker guarantees
- Using the wrong isolation level — too weak causes phantom reads, too strong kills performance
- Not understanding WAL — data durability depends on correct fsync configuration
The Interview Angle
- What does ACID stand for and why does it matter?
- What are database isolation levels?
- When would you sacrifice ACID guarantees?
- What is a write-ahead log?
Next Up
The Real-World Incident That Made This Famous
Understanding Acid Transactions became critical after multiple high-profile production incidents at major tech companies. When systems handle millions of users, even small misunderstandings about Acid Transactions can lead to cascading failures that cost millions in lost revenue and erode user trust. Companies like Netflix, Google, Amazon, and Meta have all invested heavily in mastering Acid Transactions because they learned the hard way that ignoring it leads to outages.
The key lesson from these incidents: Acid Transactions is not just a theoretical concept — it is a practical skill that separates engineers who build resilient systems from those who build fragile ones.
How Senior Engineers Think About This
Senior engineers approach Acid Transactions differently from textbook definitions. Instead of memorizing rules, they build mental models. They ask: "What problem does Acid Transactions solve? When does it fail? What are the alternatives?" This problem-first thinking leads to better design decisions because every system has unique constraints.
When evaluating Acid Transactions in a system design context, experienced engineers consider the failure modes first. What happens when this component goes down? How does the system degrade? Is the degradation graceful or catastrophic? These questions reveal more about your understanding than any textbook definition.
Common Interview Mistakes
Mistake 1: Giving a textbook definition without context. Interviewers want to see you connect Acid Transactions to real systems and real problems.
Mistake 2: Not discussing trade-offs. Every design decision involving Acid Transactions has trade-offs. Discuss what you gain and what you give up.
Mistake 3: Overcomplicating the solution. Start with the simplest approach to Acid Transactions that meets the requirements, then add complexity only when justified.
Production Checklist
- Define clear metrics for measuring the effectiveness of your Acid Transactions implementation
- Set up monitoring and alerting that specifically tracks Acid Transactions-related failures
- Document your Acid Transactions design decisions in Architecture Decision Records (ADRs)
- Test failure scenarios related to Acid Transactions in staging before production deployment
- Review and update your Acid Transactions implementation quarterly as system requirements evolve
- Train new team members on the specific Acid Transactions patterns used in your system
Read the original source | Content from System-Design-Overview
Practical Implementation for .NET Developers
In a .NET application, you would typically implement this pattern using the following approach:
ASP.NET Core setup: Create a service class that encapsulates the logic, register it with dependency injection, and inject it into your controllers or minimal API endpoints. The built-in DI container handles lifecycle management.
Entity Framework Core: For database interactions, EF Core provides the ORM layer. Use migrations for schema management and raw SQL for performance-critical queries. Consider Dapper for read-heavy paths where EF Core's overhead matters.
Azure integration: If deploying to Azure, leverage managed services — Azure Cache for Redis, Azure SQL, Azure Service Bus, Azure Cosmos DB. These eliminate operational overhead and provide built-in monitoring through Application Insights.
Testing: Use xUnit with Testcontainers for integration tests that spin up real databases in Docker. Mock external dependencies with NSubstitute. The WebApplicationFactory class lets you test your entire HTTP pipeline in-process.
Monitoring: Add Application Insights telemetry to track request latency, dependency calls, and custom metrics. Use structured logging with Serilog to make production debugging possible:
Log.Information("Processing order {OrderId} for {CustomerId}", orderId, customerId);
This gives you searchable, structured logs in Azure Monitor or Seq.