Articles

ACID Transactions Explained: Database Guarantees

ACID — atomicity, consistency, isolation, durability — defines the guarantees a database transaction makes so concurrent, failure-prone operations stay correct.

The Lycoris Team The Lycoris Team · · 4 min read
Abstract illustration representing a database

ACID is an acronym describing four guarantees a database transaction makes: atomicity, consistency, isolation, and durability. Together they define what it means for a transaction to be safe — that a group of operations either all happen or none do, that the database never ends up in a broken state, that concurrent transactions don’t corrupt each other’s results, and that a completed transaction survives a crash. Most relational databases are built around these guarantees by default; understanding them is what makes it possible to reason about what a database will and won’t protect you from.

Atomicity: all or nothing

A transaction groups multiple operations into a single unit that either fully commits or fully rolls back — there’s no partial state where some operations succeeded and others didn’t. The textbook example is a bank transfer: debiting one account and crediting another must happen together. If the debit succeeds but a crash happens before the credit, atomicity guarantees the entire transaction rolls back, leaving both accounts as if nothing happened, rather than money disappearing from the system.

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

If anything fails between BEGIN and COMMIT, the database rolls back both statements together.

Consistency: valid states only

Consistency means a transaction can only move the database from one valid state to another, respecting all defined constraints — foreign keys, unique constraints, check constraints, and any application-level invariants enforced at the database layer. A transaction that would violate a constraint (say, inserting a row that references a nonexistent foreign key) is rejected rather than partially applied. This is closely tied to database normalization, since a well-normalized schema with the right constraints is what gives the database something concrete to enforce consistency against.

Isolation: concurrent transactions don’t interfere

Isolation controls what one in-progress transaction can see of another transaction’s uncommitted changes. Without isolation, two transactions running at the same time could read each other’s half-finished work and produce corrupted results — a class of bug generally called a race condition when it shows up in concurrent systems more broadly.

Databases offer isolation levels that trade consistency guarantees against performance, since stronger isolation generally means more locking or more work resolving conflicts:

Isolation levelPrevents
Read uncommittedNothing — dirty reads possible
Read committedDirty reads
Repeatable readDirty reads, non-repeatable reads
SerializableDirty reads, non-repeatable reads, phantom reads

Serializable is the strongest level — it behaves as if every transaction ran one at a time, in some order, even though they actually ran concurrently. It’s also the most expensive, which is why most applications default to read committed or repeatable read and only reach for serializable when correctness genuinely requires it.

Durability: committed means committed

Once a transaction commits, its changes must survive a crash — a power loss or process kill immediately after commit shouldn’t lose that data. Databases achieve this by writing changes to a durable write-ahead log before acknowledging the commit, so recovery after a crash can replay the log and reconstruct any committed state that hadn’t yet been flushed to the main data files.

ACID vs BASE

ACID is the traditional model for relational databases like PostgreSQL. Many NoSQL and distributed systems instead favor BASE — Basically Available, Soft state, Eventually consistent — trading strict consistency for availability and horizontal scalability. This isn’t a strict downgrade; it’s a different point on the tradeoff space described by the CAP theorem, which formalizes why a distributed system can’t have full consistency, availability, and partition tolerance simultaneously.

ACIDBASE
ConsistencyStrong, immediateEventual
Typical systemsRelational databasesMany NoSQL and distributed systems
Availability under partitionMay sacrifice availability for consistencyFavors availability
Best forFinancial transactions, anything requiring strict correctnessHigh-scale systems where brief staleness is acceptable

This is also why the choice between SQL and NoSQL databases often comes down to whether an application needs ACID’s strict guarantees or can tolerate BASE’s eventual consistency in exchange for easier horizontal scaling. Distributed SQL databases increasingly try to offer both, and database sharding and replication strategies both have to grapple with how much ACID compliance they can preserve once data is spread across multiple nodes.

Why this matters even if you never write raw SQL

Most application developers interact with ACID guarantees indirectly, through an ORM or query builder, but the guarantees still apply underneath. Knowing that a multi-step operation needs to be wrapped in an explicit transaction — rather than issued as several independent statements — is often the difference between an application that stays correct under concurrent load and one that silently corrupts data the first time two requests race each other.

The takeaway

ACID — atomicity, consistency, isolation, and durability — is the set of guarantees that make database transactions safe to build correctness on: operations complete fully or not at all, constraints are always respected, concurrent transactions don’t see each other’s half-finished work, and committed data survives a crash. Relational databases provide these by default; understanding the tradeoffs, especially around isolation levels and the ACID-versus-BASE split in distributed systems, is what lets you choose the right guarantees for a given workload instead of assuming the strongest option is always free.

The Lycoris Team The Lycoris Team · · 5 min read

What Is a Database Trigger?

A database trigger is a procedure that runs automatically on an insert, update, or delete — enforcing rules the application layer can't guarantee.

#Databases #SQL #Backend
The Lycoris Team The Lycoris Team · · 4 min read

Primary Key vs Foreign Key vs Unique Constraint

Primary keys identify a row, foreign keys link one table to another, and unique constraints just prevent duplicates. How the three differ in SQL.

#Databases #SQL #Backend