Relational Database & ACID Transactions : Part 2

By Pradyumna Chippigiri

December 05, 2025

Series


In Part 1 of the System Design from first principles series we discussed relational databases, their history, and the “A” and “C” of ACID.


In this one, we will continue the same and discuss more about the “I” and “D” in ACID with some practical examples as well.

Isolation illustration

3. Isolation

When multiple transactions are executing in parallel, the isolation levels determine how much changes of one transaction are visible to others. Isolation ensures that concurrently running transactions do not interfere with each other’s intermediate states.


Isolation overview


If two users are updating the same row and column at the same time, whose update should “win,” and when should the other user be allowed to see that new value?


Before we talk about isolation levels, we need to understand the concurrency anomalies they’re trying to prevent. These are the weird, unintuitive things that can happen when multiple transactions run at the same time.


Dirty read


Dirty read


Non-repeatable read


Non-repeatable read


Phantom read


Note: This is different from non-repeatable reads because in non-repeatable reads, values in the same row change, but in phantom reads, new rows are added or deleted.

Phantom read


Isolation levels

Now that we’ve seen the anomalies (dirty reads, non-repeatable reads, lost updates, phantom reads), we can finally talk about isolation levels.


When multiple transactions run in parallel, the isolation level is basically the database’s answer to:


“How much of Transaction B’s work is Transaction A allowed to see (and when), and which anomalies are we willing to tolerate for the sake of performance?”

Repeatable read

Consistent reads within the same transaction. The idea is: “If I read a row once in my transaction, I want to see the same value every time I read that row again.”


At repeatable read:

Now I start two transactions T1 and T2, concurrently. In the image below, let’s say the left transaction is T1 and the right transaction is T2.


This is how we check the isolation level (I’ve used MySQL; you can check the documentation for other databases.)

Repeatable read check


Here I update a row in T1 (and I haven’t committed yet), and if I read the same row from T2, T2 would still show the older value of the row (consistent read).

Repeatable read update


And now if I commit T1, and re-read the same row in T2 then again it would still read the same old value (haven’t committed T2 yet). So this proves that repeatable read is opaque to whatever has been done elsewhere in the system it still gives a stable consistent read value.

Repeatable read commit

Read committed

So at read committed:

Setting the isolation level for both transactions to READ COMMITTED.

Read committed level


Read committed update

Read uncommitted

So at read uncommitted, the database allows:

Now again we will set the isolation level to READ UNCOMMITTED.

Read uncommitted level


Read uncommitted update


As you see we haven’t committed yet in T2.

Serializable

So at serializable:

Serializable level


Serializable wait


As you can see this is what we mean by strict isolation level, as we haven’t committed or rolled back T1 yet, T2 just waits there until a COMMIT or a ROLLBACK operation happens.


So to summarize this is how the isolation level and concurrency anomalies relate to:

Isolation summary


Now, coming to durability.

Durability

Once a transaction commits successfully, its changes must survive crashes, restarts, and power failures. The database is not allowed to forget a committed transaction.

How databases ensure durability


You can read more about WAL here: WAL article


Synchronous replication


Writes are sent to multiple nodes or data centers immediately. A transaction is only marked as committed when the primary and at least one replica (or a quorum, depending on the system) confirm that the data is safely stored. This reduces the risk of data loss if the primary fails right after commit.


Asynchronous replication


The primary node commits locally first and then ships changes to replicas in the background. This improves latency, but creates a small window where recent writes may be lost if the primary fails before the replicas have been updated.


Replication Strategies


Regular backups provide a safety net beyond logs and replication. In case of severe corruption, human error, or catastrophic failure:



Hope you got a clear understanding of what ACID transactions are and how all of this works behind the scenes.


If you learned something out of this then please do like and subscribe, this really would give me more motivation to create such in depth deep dives.


Take care and see you in the next one.