nuttingd
Joined 10 years ago
Joined 10 years ago
In Postgres, even with the serializable isolation level, all transactions that touch the same rows must also be using the serializable isolation level or it's not really enforced. This is one aspect of serializable isolation in Postgres that seemed like a major gotcha for real world application development. There's no future proof solution: new code can be added that doesn't use the serializable isolation, and then the assumptions of isolation from the earlier code are no longer valid.
FOR UPDATE is the only real solution in my eyes
import my_module
This is compatible with `__all__` if you have your code broken down into smaller sub-modules and collect them in the main module as follows: # my_module/__init__.py
from .submodule import *
from .another_submodule import *Agreed. The concepts are all very simple. You can throw away all of the domain-specific terminology and reason about accounting theory with nothing but positive and negative numbers.
The utility of the confusing terminology and age old accounting frameworks isn't obvious unless you are a practitioner living "in it". It's not until you face the complexities of real world transactions (an accountant booking closing entries for a F500 company or something) that the strange left/right debit/credit way of thinking is very valuable.
Assets | Liabilities + Equity
Accounts classified as assets are debit accounts (left side), and accounts classified as liabilities or equity are credit accounts (right side).
The theory discussed everywhere in this thread is sound. You really don't need to use terminology like debit/credit for accounting.
What the discussion misses is the application of this framework. It is useful for a human to be able to visualize a complex transaction and work through missing pieces with the hints this framework provides. I'm missing something on the left? Oh yeah, I missed the deferred revenue debit.
Quoted from Page 70:
If you use the Serializable level, it must be observed by all transactions of the application. When combined with other levels, Serializable behaves as Repeatable Read without any notice. So if you decide to use the Serializable level, it makes read sense to modify the default_transaction_isolation parameter value accordingly -- even though someone can still overwrite it by explicitly setting a different level.
I had a real "WTF?" moment when I read this the first time.
This is a bit jarring if you come from MSSQL, which implements the SERIALIZABLE isolation level using locks. In MSSQL, you can rest assured that a serializable transaction will not be affected by changes from other concurrent transactions, regardless of their isolation level.
In Postgres, you may have a set of transactions all participating in SERIALIZABLE isolation today, but tomorrow someone adds another script without the SERIALIZABLE isolation level, and now your protected paths are no longer isolated.
Sprint "commitments" in my world. A single word with major psychological impacts.
The balance would still be wrong for the whole range where balance > 0. Two (positive) deposits would not store the correct ending balance.
I think pagination is only predictable under these conditions:
1) The offset used for the next fetch must be based on a pointer to a unique key. We can't rely on the number of rows previously seen.
With this rule, deletes which occur to rows in previous pages will not cause unpredictable contractions.
2) The paged result set must be sorted based on a monotonically increasing field, like created_at, plus enough other fields to create a unique key. You could lean on the PK for this, i.e.: ORDER BY (created_at, id) ASC.
With this rule, new inserts which occur during page enumeration will only affect unseen pages (and we'll see them eventually)
The API call looks roughly like this:
/orders/?region=US&offset=(2022-03-12T07:05:58Z&ord_1234)&limit=100
The DB query looks roughly like this: SELECT *
FROM orders
WHERE (created_at, id) > (:offset_created_at, :offset_id)
OR (
:offset_created_at IS NULL
AND :offset_id IS NULL
)
ORDER BY (created_at, id) ASC
LIMIT :page_size
EDIT: formatting
- https://github.com/nuttingd