In the last lesson, two customers grabbed the last coupon at the same moment and both got it. Every transaction was atomic and durable, and the data was still wrong. The culprit was isolation: how much one running transaction can see or affect another.
The ideal is simple. Transactions should behave as if they ran one at a time. But running them one at a time is slow, so databases offer weaker isolation levels that let more work happen in parallel and allow certain kinds of interference, called anomalies.
This lesson names each anomaly with a Tiffin example, maps them to the levels, and then shows what Postgres and MySQL really do, because their behaviour doesn't match the SQL standard's names as closely as you'd hope.
The ideal, and why nobody defaults to it
A schedule is serializable if its result is the same as running the transactions one after another, in some order.
Note "in some order". The database doesn't promise the order you'd expect, only that the outcome matches some one-at-a-time order.
Getting this guarantee costs something. Either transactions wait for each other's locks, or the database watches for dangerous patterns and aborts one of them, which your code must retry. Under heavy contention that means lower throughput and more errors. So vendors default to something weaker and let you opt in.