Stop Messing with Database Commits and Transactions

A stray commit buried multiple levels deep cost me months

I discovered that random manual commits hidden deep in my codebase were breaking atomicity, causing data loss despite using transaction managers. The solution is strict: the database abstraction layer must own all commits and transactions. Never pass database models outside this layer, avoid manual commits, and enforce these rules using AST analysis or LLM checks to prevent silent failures.

The DB abstraction layer owns the commits and transactions. Everything else is a workaround for getting that wrong.
  1. Groxx

    # transaction has been commented out

    # with transaction():

    db_models = DBAccess.fetch_records(ids)

    db_models[0].yo_mama_fat = True

    # request ends, data poofs into the ether

    tbh if this doesn't fail either immediately (no open transaction == error on modification attempt) or at GC time (if there's some kind of deferred logic), then I'd say this is an extremely bad framework and it does hold a major part of the blame. "You can mutate database-connected objects and sometimes they save back to the DB, sometimes they do not" is not reasonable behavior.

    (obviously these frameworks exist. quite a few of them. quantity does not in any way imply sanity.)

    > 2. DO NOT pass DB models in and out of the DB layer.

    Yea, the more I've used "thin" ORMs that give you plain objects, the more I've grown convinced they're the best choice basically all the time. Trying to be magical is cute, but it's guaranteed to be made of spicy unobtanium, and at some point it'll blow up in your face in an extremely convoluted way due to a simple cause that you'll notice is absolutely everywhere and you're just stuck being paranoid forever. There's no need to live like that.

  2. Retr0id

    > DO NOT blame the framework

    Why not? Why should I be allowed to db.commit() midway through a transaction?

  3. magicalhippo

    I found the article very hard to follow. Then I read the domain name and it all made sense...

    Guess our pattern is different, not really felt the pain point the author is talking about. Or it's the language/framework, not sure whatever the example code is written in, but setting properties on entity records would never update the database in the ones I've used.

    When we did things more manually we'd make sure that methods like `create_main_records` would start a transaction if not in one, and only commit if it started the transaction. This way we could nest without worry. Our database supported nested transactions but using this pattern we didn't feel the need.

More from this day

2026-08-02