{
  "slug": "read-committed-isolation",
  "term": "Read Committed isolation",
  "aliases": [
    "Read Committed",
    "READ COMMITTED"
  ],
  "definition": "Read Committed is a transaction isolation level that excludes dirty reads but can allow later statements to observe changes committed by other transactions.",
  "note": "The level does not require a particular concurrency-control mechanism. Berenson et al. distinguish phenomenon-based definitions from locking implementations; a shared label is not evidence of identical behavior. Nonrepeatable reads and phantoms remain possible. [berenson-isolation]\n\nIn PostgreSQL 18, an ordinary SELECT uses a statement-start snapshot and sees its own transaction's previous writes. Successive statements can therefore see different committed states. Updating commands have additional concurrent-row recheck behavior; do not generalize the ordinary-read rule to every command. [postgres-isolation]\n\nIsolation and persistence answer different questions. Choosing this level does not specify a failure model, backup policy or durable acknowledgement boundary. See the companion analysis for a constructed two-read history. [hesela-consistency]\n\nPostgreSQL ON CONFLICT DO NOTHING can reject a proposed insertion because of a row outside the statement snapshot. A fallback SELECT in the same data-modifying WITH statement need not find that row; a later command obtains a new Read Committed snapshot. [postgres-conflict16] [postgres-with16]\n\nHesela's ten controlled PostgreSQL 16.15 cases, each captured twice on one host/build, include an empty get-or-create result after a competing commit. An unchanged-value DO UPDATE returned the identity but fired row and statement UPDATE triggers; WHERE false returned no identity but still fired the statement trigger. A deletion before the next lookup made it empty again. This is neither a new database defect nor an unconditional retry guarantee. Native observations, code and raw captures are available in the reproduction packet. [postgres-insert16] [postgres-triggers16] [hesela-conflict-evidence]",
  "related": [
    "snapshot-isolation",
    "read-atomic-isolation",
    "serializability",
    "fractured-read"
  ],
  "status": "unknown",
  "advantages": [],
  "limitations": [
    "A conditional conflict UPDATE still locks the conflicting row even when its predicate prevents a row update; it is not a lock-free lookup. This is a documented boundary, not a lock-duration measurement. [postgres-insert16]"
  ],
  "supersedes": [],
  "supersededBy": [],
  "firstSeen": null,
  "lastSeen": null,
  "updated": "2026-11-13",
  "citations": [
    {
      "id": "berenson-isolation",
      "title": "Berenson et al. A Critique of ANSI SQL Isolation Levels. SIGMOD 1995; MSR-TR-95-51, sections 2.2-2.3, Tables 1-2.",
      "url": "https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr-95-51.pdf",
      "accessed": "2026-11-13"
    },
    {
      "id": "postgres-isolation",
      "title": "PostgreSQL 18 documentation: Transaction Isolation, section 13.2.1.",
      "url": "https://www.postgresql.org/docs/18/transaction-iso.html#XACT-READ-COMMITTED",
      "accessed": "2026-11-13"
    },
    {
      "id": "hesela-consistency",
      "title": "Hesela: Storage consistency, ordering, transactions and durability.",
      "url": "https://hesela.com/analyses/storage-consistency-ordering/#read-committed",
      "accessed": "2026-11-13"
    },
    {
      "id": "postgres-conflict16",
      "title": "PostgreSQL 16: Transaction Isolation, sections 13.2.1-13.2.2; conflict visibility and transaction restart.",
      "url": "https://www.postgresql.org/docs/16/transaction-iso.html",
      "accessed": "2026-11-13"
    },
    {
      "id": "postgres-with16",
      "title": "PostgreSQL 16: WITH Queries, section 7.8.4; shared snapshots and RETURNING.",
      "url": "https://www.postgresql.org/docs/16/queries-with.html#QUERIES-WITH-MODIFYING",
      "accessed": "2026-11-13"
    },
    {
      "id": "postgres-insert16",
      "title": "PostgreSQL 16: INSERT; RETURNING and rows locked but not updated.",
      "url": "https://www.postgresql.org/docs/16/sql-insert.html",
      "accessed": "2026-11-13"
    },
    {
      "id": "postgres-triggers16",
      "title": "PostgreSQL 16: Overview of Trigger Behavior, section 39.1; statement-level conflict UPDATE triggers.",
      "url": "https://www.postgresql.org/docs/16/trigger-definition.html",
      "accessed": "2026-11-13"
    },
    {
      "id": "hesela-conflict-evidence",
      "title": "Hesela: PostgreSQL 16.15 conflict-visibility observations, executable protocol and raw evidence.",
      "url": "https://hesela.dev/research/read-committed-native/read-committed-native.zip",
      "accessed": "2026-11-13"
    }
  ],
  "provenance": [
    "Original level definition and PostgreSQL 18 explanation are primary-source synthesis. A separate native PostgreSQL 16.15 supplement records ten prescribed cases in two same-host/build clusters; not a general conformance test or independent replication."
  ]
}
