{
  "slug": "dirty-read",
  "term": "Dirty read",
  "aliases": [
    "Uncommitted read"
  ],
  "definition": "A dirty read occurs when one transaction reads data written by another transaction before the writer commits.",
  "note": "The writer need not eventually abort for the read to be dirty. The relevant boundary is its uncommitted state at the time of the read. A later rollback makes the practical risk explicit, because the reader may already have acted on a value that never became committed. [postgres-isolation]\n\nThis differs from a nonrepeatable read, where a later statement can observe another transaction's committed change. Reading one's own previous writes is also not a cross-transaction dirty read. Read Committed excludes the phenomenon for ordinary transactional data; Read Uncommitted permits it but an implementation can be stronger. [postgres-isolation]\n\nIn SQLite, a shared cache and PRAGMA read_uncommitted on the reader are both needed to expose another connection's pending writes. Private-cache readers remain isolated even with the pragma enabled. [sqlite-isolation] [sqlite-read-uncommitted]\n\nThe companion example observes a pending value and then the original value after rollback. That is an isolation demonstration, not a test of storage persistence or a recommendation to enable shared-cache mode. [hesela-consistency] [sqlite-shared-cache]\n\nBerenson et al. distinguish broad P1 from narrow A1: P1 does not require abort, whereas A1 includes a writer abort and reader commit. Checking only rolled-back writes misses the broader phenomenon. [berenson-isolation]",
  "related": [
    "read-uncommitted-isolation",
    "read-committed-isolation"
  ],
  "status": "unknown",
  "advantages": [],
  "limitations": [],
  "supersedes": [],
  "supersededBy": [],
  "firstSeen": null,
  "lastSeen": null,
  "updated": "2026-11-13",
  "citations": [
    {
      "id": "postgres-isolation",
      "title": "PostgreSQL 18: Transaction Isolation, Table 13.1 and section 13.2.1.",
      "url": "https://www.postgresql.org/docs/18/transaction-iso.html",
      "accessed": "2026-11-13"
    },
    {
      "id": "sqlite-isolation",
      "title": "SQLite: Isolation Between Database Connections.",
      "url": "https://www.sqlite.org/isolation.html",
      "accessed": "2026-11-13"
    },
    {
      "id": "sqlite-read-uncommitted",
      "title": "SQLite: PRAGMA read_uncommitted.",
      "url": "https://www.sqlite.org/pragma.html#pragma_read_uncommitted",
      "accessed": "2026-11-13"
    },
    {
      "id": "sqlite-shared-cache",
      "title": "SQLite: Shared-Cache Mode, sections 1.1 and 2.2.1-2.3.",
      "url": "https://www.sqlite.org/sharedcache.html",
      "accessed": "2026-11-13"
    },
    {
      "id": "hesela-consistency",
      "title": "Hesela: Read Uncommitted depends on the engine and connection setup.",
      "url": "https://hesela.com/analyses/storage-consistency-ordering/#read-uncommitted",
      "accessed": "2026-11-13"
    },
    {
      "id": "berenson-isolation",
      "title": "Berenson et al. A Critique of ANSI SQL Isolation Levels. SIGMOD 1995; MSR-TR-95-51, section 2.2 and section 3, H1.",
      "url": "https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr-95-51.pdf",
      "accessed": "2026-11-13"
    }
  ],
  "provenance": [
    "Primary-source explanation of cross-transaction visibility. No claim that all engines expose dirty reads when the level is requested; own writes and nontransactional engine objects require separate interpretation."
  ]
}
