Imagine you’re running an e-commerce application.
A customer places an order, and your system needs to deduct the item from inventory, charge the customer’s credit card, and record the sale in your accounting system—all at once.
What happens if the payment fails but your inventory count has already been reduced? Or if your application crashes halfway through the process?
This is where ACID transactions come into play. They ensure that all the steps in such critical operations happen reliably and consistently.
ACID is an acronym that refers to the set of 4 key properties that define a transaction: Atomicity, Consistency, Isolation, and Durability.
In this article, we’ll dive into what each of the ACID properties mean, why they are important, and how they are implemented in databases.
A transaction in the context of databases is a sequence of one or more operations (such as inserting, updating, or deleting records) that the database treats as one single action. It either fully succeeds or fully fails, with no in-between states.
Example: Bank Transfer
When you send money to a friend, two things happen:
These two steps form one transaction. If either step fails, both are canceled.
Without transactions, databases could end up in inconsistent states.
For example:
Transactions solve these problems by enforcing rules like ACID properties (Atomicity, Consistency, Isolation, Durability).
Now, lets looks at each of the ACID properties.
Atomicity ensures that a transaction—comprising multiple operations—executes as a single and indivisible unit of work: it either fully succeeds (commits) or fully fails (rolls back).
If any part of the transaction fails, the entire transaction is rolled back, and the database is restored to a state exactly as it was before the transaction began.
Example: In a money transfer transaction, if the credit step fails, the debit step cannot be allowed to stand on its own. This prevents inconsistent states like “money disappearing” from one account without showing up in another.
Atomicity abstracts away the complexity of manually undoing changes if something goes wrong.
Databases use two key mechanisms to guarantee atomicity.
Example:
Once the WAL entry is safely on disk, the database proceeds with modifying the in-memory pages that contain rows for Account A and Account B.
When the operations succeed:
If the database crashes after the log entry is written but before the data files are fully updated, the WAL provides a way to recover:
If the transaction had not committed (or was marked as “in progress”) at the time of the crash, the database would roll back those changes using information in the log, leaving the table as if the transaction never happened.
BEGIN TRANSACTION
, COMMIT
, and ROLLBACK
BEGIN TRANSACTION
and COMMIT
are considered “in-progress” and won’t be permanently applied unless the transaction commits successfully.ROLLBACK
, all changes since the start of the transaction are undone.Example:
Consistency in the context of ACID transactions ensures that any transaction will bring the database from one valid state to another valid state—never leaving it in a broken or “invalid” state.
It means that all the data integrity constraints, such as primary key constraints (no duplicate IDs), foreign key constraints (related records must exist in parent tables), and check constraints (age can’t be negative), are satisfied before and after the transaction.
If a transaction tries to violate these rules, it will not be committed, and the database will revert to its previous state.
You have two tables in an e-commerce database:
products
(with columns: product_id
, stock_quantity
, etc.)orders
(with columns: order_id
, product_id
, quantity
, etc.)Constraint: You can’t place an order for a product if quantity
is greater than the stock_quantity
in the products
table.
stock_quantity
was 8 (less than what we’re trying to order), the database sees that the new value would be -2
which breaks the consistency rule (it should not go negative).Isolation ensures that concurrently running transactions do not interfere with each other’s intermediate states.
Essentially, while a transaction is in progress, its updates (or intermediate data) remain invisible to other ongoing transactions—giving the illusion that each transaction is running sequentially, one at a time.
Without isolation, two or more transactions could read and write partial or uncommitted data from each other, causing incorrect or inconsistent results.
With isolation, developers can reason more reliably about how data changes will appear to other transactions.
To understand how isolation works, it helps to see what can go wrong without proper isolation. Common concurrency anomalies include:
Databases typically allow you to choose an isolation level, which balances data correctness with performance.
Higher isolation levels provide stronger data consistency but can reduce system performance by increasing the wait times for transactions.
Let's explore the four common isolation levels:
Example:
Example:
Example:
Example:
Durability ensures that once a transaction has been committed, the changes it made will survive, even in the face of power failures, crashes, or other catastrophic events.
In other words, once a transaction says “done,” the data is permanently recorded and cannot simply disappear.
Most relational databases rely on a Write-Ahead Log (WAL) to preserve changes before they’re written to the main data files:
If the database crashes, it uses the WAL during recovery:
In addition to WAL, many systems use replication to ensure data remains durable even if hardware or an entire data center fails.
Regular backups provide a safety net beyond logs and replication. In case of severe corruption, human error, or catastrophic failure: