Systems

Dirty Reads, Explained

A dirty read returns an uncommitted value from another transaction. If that transaction rolls back, the reader observed a value that was never part of committed database state.

Rickvian Aldi·Software engineer·August 8, 2026·5 min read

Co-authored with generative AI

Account 42 starts with a committed balance of $500. Transaction A is a payment service attempting to debit the account, so it updates the balance to $0 while it validates the payment. Transaction B is the account dashboard, which reads the balance to display it to the customer. If Transaction A later rolls back, the balance returns to $500, but Transaction B has already displayed $0.

That is a dirty read: one transaction reads another transaction's uncommitted changes.

The initial state

Before either transaction starts, the database contains one committed row:

Account IDBalance
42$500

Transaction A owns the payment attempt. Its update is not committed because payment validation is still in progress. Transaction B only wants to display the current balance. It is configured with READ UNCOMMITTED, so it can read Transaction A's unfinished update.

The two-transaction problem

Transactions normally prevent one session from reading another session's unfinished changes. A dirty read allows that access, which can reduce waiting but exposes an intermediate database state.

A dashboard reads a payment transaction's uncommitted balance before payment validation fails.

The dashboard displayed 0, even though the committed balance remained $500 throughout. If Transaction B uses the value to approve another withdrawal, send an email, or populate a cache, a downstream operation can use data from a transaction that later rolled back.

A small SQL example

MySQL supports the READ UNCOMMITTED isolation level, which permits this behavior:

-- Initial committed state: account 42 has a balance of 500.
 
-- Session A: payment service starts a debit.
START TRANSACTION;
UPDATE accounts SET balance = 0 WHERE id = 42;
-- Payment validation is still in progress. The update is uncommitted.
 
-- Session B: account dashboard reads the balance while Session A is open.
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;
SELECT balance FROM accounts WHERE id = 42;
-- Result: 0
 
-- Session A: payment validation fails, so the debit is cancelled.
ROLLBACK;
-- The committed balance remains 500.

The exact syntax and behavior vary by database. InnoDB permits dirty reads at READ UNCOMMITTED. PostgreSQL accepts the label but maps it to READ COMMITTED, so this example does not produce a dirty read there. Oracle does not support READ UNCOMMITTED. Always verify the isolation semantics of the database engine and driver in use instead of assuming that a standard isolation-level name has identical behavior everywhere.

Why anyone enables it

The trade-off is simple: potentially less waiting in exchange for weaker correctness. A reader at READ UNCOMMITTED may avoid waiting for a writer's commit, but this is an implementation detail, not a guarantee that the query never blocks. The setting can look attractive for a low-value report or a heavily contended table.

The cost is not just an incorrect number. The reader can observe an intermediate state, read a row that later disappears, or make a decision before the writer commits. A retry can return a different answer immediately afterward, making the problem difficult to reproduce.

When not to use it

Do not use dirty reads for money, inventory, permissions, quotas, job state, or any decision that triggers an external side effect. A faster query is not useful if it causes a payment, reservation, or notification based on data that gets rolled back.

For most application reads, start with the database engine's documented default isolation level. Defaults differ: PostgreSQL defaults to READ COMMITTED, while InnoDB defaults to REPEATABLE READ. If a report needs a stable view without blocking writers, investigate snapshot-based isolation or a replica, and measure the freshness, version-retention, and operational costs.

Gotchas and alternatives

The common mistake is treating READ UNCOMMITTED as a harmless performance switch. It changes which database states the application can observe. In multiversion concurrency control (MVCC) engines, ordinary snapshot reads and locking reads can also have different behavior, so the isolation level alone is not the whole concurrency model. Connection pools create an additional configuration risk: isolation settings can persist on a reused connection, so set and reset them deliberately.

The main alternatives are:

  • READ COMMITTED: read only committed data, but separate statements can see different committed versions.
  • REPEATABLE READ: commonly keep a consistent snapshot for ordinary reads in a transaction, but details such as locking reads and write conflicts vary by engine.
  • SERIALIZABLE: provide the strongest isolation, at the cost of more waits, aborts, or transaction retries.
  • A read replica or precomputed report: move analytical work away from the primary, accepting replication lag.

References

Takeaway

A dirty read exposes an uncommitted value, so use it only when the application can tolerate results that may be rolled back before they become committed state.

Related essays

Systems

Non-Repeatable Reads, Explained

A transaction reads the same row twice and gets two different committed values. The isolation level determines whether both reads use the same database state.

Aug 8, 2026·5 min read
Systems

Phantom Reads, Explained

A transaction repeats a search and finds an additional matching row. The existing rows did not change, but another transaction committed a new row that satisfies the same query.

Aug 8, 2026·9 min read
Systems

E2E and SSL Encryption Are Different

A green lock only proves one network hop is protected. End-to-end encryption moves the trust boundary so the server can carry a message without being able to read it.

Jun 15, 2026·9 min read

Get essays in your inbox

Practical deep-dives on software craft, career leverage, and building things that matter.