{
  "slug": "repeatable-read-isolation",
  "term": "Repeatable Read isolation",
  "aliases": [
    "Repeatable Read",
    "REPEATABLE READ"
  ],
  "definition": "Repeatable Read is a transaction isolation level whose SQL minimum forbids dirty and nonrepeatable reads without requiring phantom-free or serializable execution.",
  "note": "Implementations may be stronger than the SQL minimum; the name is not a portable synonym for snapshot isolation. PostgreSQL 18 prevents phantoms and uses the snapshot from the first non-transaction-control statement, plus the transaction's own writes, but serialization anomalies remain possible. [postgres-isolation]\n\nMySQL 8.4 InnoDB normally establishes the snapshot at the first consistent nonlocking read. Locking reads and UPDATE or DELETE use a different visibility boundary; a write can affect rows hidden from an earlier ordinary SELECT. Own writes remain visible. [mysql-consistent] [mysql-isolation]\n\nSTART TRANSACTION WITH CONSISTENT SNAPSHOT can establish the InnoDB snapshot at transaction start; the modifier does not change the isolation level and is effective only at Repeatable Read. [mysql-start]\n\nTo recover from a PostgreSQL serialization failure with SQLSTATE 40001, retry the complete transaction, including its decisions, and another attempt can fail. Repeatable Read does not guarantee serializability or specify crash durability. [postgres-retry] [postgres-isolation]\n\nA snapshot does not freeze table storage. PostgreSQL TRUNCATE and table-rewriting ALTER TABLE can leave a table empty to an older snapshot that had not accessed it; prior access holds an ACCESS SHARE lock that blocks the DDL. [postgres-mvcc-caveats]\n\nInnoDB consistent reads do not span DROP TABLE or copy-based ALTER TABLE that replaces the original table; the latter can return ER_TABLE_DEF_CHANGED and require a transaction retry. [mysql-consistent]\n\nPostgreSQL 16.15 COPY FREEZE exposed later rows to an old snapshot after loader commit; same-host tests, not independent replication. [postgres-copy16-native] [hesela-mvcc-native]",
  "related": [
    "snapshot-isolation",
    "read-committed-isolation",
    "serializability",
    "serializable-snapshot-isolation",
    "write-skew"
  ],
  "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.2.",
      "url": "https://www.postgresql.org/docs/18/transaction-iso.html",
      "accessed": "2026-11-13"
    },
    {
      "id": "postgres-retry",
      "title": "PostgreSQL 18: Serialization Failure Handling, section 13.5.",
      "url": "https://www.postgresql.org/docs/18/mvcc-serialization-failure-handling.html",
      "accessed": "2026-11-13"
    },
    {
      "id": "mysql-consistent",
      "title": "MySQL 8.4: Consistent Nonlocking Reads, section 17.7.2.3.",
      "url": "https://dev.mysql.com/doc/refman/8.4/en/innodb-consistent-read.html",
      "accessed": "2026-11-13"
    },
    {
      "id": "mysql-isolation",
      "title": "MySQL 8.4: InnoDB Transaction Isolation Levels, section 17.7.2.1.",
      "url": "https://dev.mysql.com/doc/refman/8.4/en/innodb-transaction-isolation-levels.html",
      "accessed": "2026-11-13"
    },
    {
      "id": "mysql-start",
      "title": "MySQL 8.4: START TRANSACTION, COMMIT, and ROLLBACK Statements, section 15.3.1.",
      "url": "https://dev.mysql.com/doc/refman/8.4/en/commit.html",
      "accessed": "2026-11-13"
    },
    {
      "id": "postgres-mvcc-caveats",
      "title": "PostgreSQL 18: MVCC Caveats, section 13.6.",
      "url": "https://www.postgresql.org/docs/18/mvcc-caveats.html",
      "accessed": "2026-11-13"
    },
    {
      "id": "hesela-consistency",
      "title": "Hesela: Repeatable Read needs an engine and a statement type.",
      "url": "https://hesela.com/analyses/storage-consistency-ordering/#repeatable-read",
      "accessed": "2026-11-13"
    },
    {
      "id": "postgres-copy16-native",
      "title": "PostgreSQL 16: COPY, FREEZE option.",
      "url": "https://www.postgresql.org/docs/16/sql-copy.html",
      "accessed": "2026-11-13"
    },
    {
      "id": "hesela-mvcc-native",
      "title": "Hesela: PostgreSQL 16.15 heap replacement and frozen import, method and reproduction commands.",
      "url": "https://hesela.dev/research/mvcc-rewrite-native/README.md",
      "accessed": "2026-11-13"
    }
  ],
  "provenance": [
    "Primary-documentation synthesis accessed 2026-11-13; not a native-engine experiment or an original measurement. SQL minimum is reported via PostgreSQL Table 13.1; the ISO standard was not independently inspected.",
    "PostgreSQL 18 and MySQL 8.4 InnoDB behavior is scoped separately to ordinary transactional-table reads and writes. No database-wide frozen-state or backup guarantee is claimed.",
    "Separate native supplement: twelve PostgreSQL 16.15 cases; synthetic inputs, native results and same-host replay, not independent replication or PostgreSQL 18 execution. All target reads follow writer completion. Earlier PostgreSQL 18/MySQL 8.4 comparison remains documentation synthesis."
  ]
}
