--- /dev/null
+This repository contains examples of problems that might arise if developers are not aware
+of the different isolation levels in databases.
+
+We use PostgreSQL specifically here. Consult your vendor for details on their isolation levels.
+Relevant Postgres 17 docs on isolation levels: https://www.postgresql.org/docs/current/transaction-iso.html.
+
+## Read-commited
+
+- [Example](./read_commited.py)
+
+This level uses snapshots for each separate command. A query that acts based on previously read data
+might be using stale data if another transaction committed a mutation to values read by the
+previous select.
--- /dev/null
+services:
+ db:
+ image: postgres:17
+ environment:
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: postgres
+ POSTGRES_DB: postgres
+ volumes:
+ - ./schema.sql:/docker-entrypoint-initdb.d/schema.sql
+ ports:
+ - "5432:5432"
--- /dev/null
+import records
+
+
+db = records.Database("postgresql://postgres:postgres@localhost/postgres")
+
+# Scenario: We want to transfer $10 from Bob to Alice
+# NOTE: Both users' balance is initially set to 10.
+
+c1, c2 = db.get_connection(), db.get_connection()
+t1, t2 = c1.transaction(), c2.transaction()
+
+# We read Bob's balance
+bob_balance = (
+ c1.query("select amount from balance where username = 'bob'").first().amount
+)
+
+# In another transaction, Bob's balance was set to 0 (maybe a transfer to another user).
+# This transaction commits.
+c2.query("update balance set amount = 0 where username = 'bob'")
+t2.commit()
+
+# We use the value we read before for the test.
+if bob_balance >= 10:
+ # And update the balances accordingly if the condition holds.
+ c1.query("update balance set amount = amount - 10 where username = 'bob'")
+ c1.query("update balance set amount = amount + 10 where username = 'alice'")
+ t1.commit()
+
+bob_balance = (
+ c1.query("select amount from balance where username = 'bob'").first().amount
+)
+
+alice_balance = (
+ c1.query("select amount from balance where username = 'alice'").first().amount
+)
+
+c1.close()
+c2.close()
+
+# What will the final balances be?
+print("Bob: " + str(bob_balance))
+print("Alice: " + str(alice_balance))
--- /dev/null
+create table balance (
+ username text not null,
+ amount decimal not null default 0,
+
+ primary key (username)
+);
+
+insert into balance
+values ('bob', 10), ('alice', 10);