<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/row-locking-in-sqlalchemy-ppvuyvdl3" -->

---
title: Row locking in SQLAlchemy | daily.dev
description: A common SQLAlchemy pitfall is explained: using with_for_update() to lock a row that is already present in the session's identity map (e.g., loaded earlier via...
canonical: https://daily.dev/posts/row-locking-in-sqlalchemy-ppvuyvdl3
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Row locking in SQLAlchemy | daily.dev
og:description: A common SQLAlchemy pitfall is explained: using with_for_update() to lock a row that is already present in the session's identity map (e.g., loaded earlier via...
og:url: https://daily.dev/posts/row-locking-in-sqlalchemy-ppvuyvdl3
og:image: https://api.daily.dev/og/posts/ppvuyVDL3.png
og:image:alt: Row locking in SQLAlchemy
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Row locking in SQLAlchemy

**[scopespace](https://daily.dev/sources/scope_space)** · [@fab978](https://daily.dev/fab978) · 1 min read · 4 upvotes · 0 comments

## Summary

A common SQLAlchemy pitfall is explained: using with_for_update() to lock a row that is already present in the session's identity map (e.g., loaded earlier via selectinload) returns the stale cached object instead of the freshly locked database values, even though the lock itself succeeds. Developers may believe they have the latest, locked state when they are actually still working with outdated data.

## Content

Been a while since I posted anything here.

Today I want to share a small but useful pattern for row locking in SQLAlchemy when the object might already be in the session.

Most of the time, people just write something like this:

vehicle = session.query(Vehicle).filter_by(id=vehicle_id).with_for_update().one()

That works fine if the object isn’t already loaded. The problem starts when the vehicle came in earlier through a selectinload or some other relationship. 

SQLAlchemy already has that object sitting in the identity map. The locked query still runs against the database, but you get back the old cached version instead of the fresh values that came with the lock.

You end up thinking you locked the row and read the latest state, when in reality you’re still looking at stale data.

Full Article :  [https://lnkd.in/p/g5k_ScKu](https://lnkd.in/p/g5k_ScKu)

## Similar posts on daily.dev

- [Why I Keep Reaching for SQLAlchemy](https://daily.dev/posts/why-i-keep-reaching-for-sqlalchemy-mqcgfdq9w) · Atomic Spin · 0 upvotes · 0 comments
- [Row locks at the page level](https://daily.dev/posts/row-locks-at-the-page-level-o9spsmh7b) · Planet PostgreSQL · 0 upvotes · 0 comments
- [How to Prevent Race Conditions in Django](https://daily.dev/posts/how-to-prevent-race-conditions-in-django-mrablcwec) · freeCodeCamp · 0 upvotes · 0 comments
- [Optimistic Locking vs Pessimistic Locking](https://daily.dev/posts/optimistic-locking-vs-pessimistic-locking-tnez3fjrn) · Towards Dev · 25 upvotes · 0 comments

---

Tags: [#python](https://daily.dev/tags/python), [#backend](https://daily.dev/tags/backend)

[View this post on daily.dev](https://daily.dev/posts/row-locking-in-sqlalchemy-ppvuyvdl3)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"DiscussionForumPosting","mainEntityOfPage":"https://daily.dev/posts/row-locking-in-sqlalchemy-ppvuyvdl3","headline":"Row locking in SQLAlchemy","text":"A common SQLAlchemy pitfall is explained: using with_for_update() to lock a row that is already present in the session's identity map (e.g., loaded earlier via selectinload) returns the stale cached object instead of the freshly locked database values, even though the lock itself succeeds. Developers may believe they have the latest, locked state when they are actually still working with outdated data.","url":"https://daily.dev/posts/row-locking-in-sqlalchemy-ppvuyvdl3","datePublished":"2026-10-02T16:03:29.102Z","dateModified":"2026-10-02T16:03:56.959Z","author":{"@type":"Person","name":"Furqan ahmad","url":"https://daily.dev/fab978","image":"https://media.daily.dev/image/upload/s--GY0VPIs1--/f_auto/v1788339486/avatars/avatar_01YKXdhx6XxiWycQaD2rh?_a=BAMAMicg0","description":"\nFull Stack & Backend Developer | Open to Remote Opportunities","interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"EndorseAction"},"userInteractionCount":4080}},"image":"https://media.daily.dev/image/upload/s--2u4XDaAv--/f_auto/v1790957009/posts/ppvuyVDL3?_a=BAMAMicg0","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":4},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"isPartOf":{"@type":"WebPage","url":"https://daily.dev/squads/scope_space","name":"scopespace"}}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"scopespace","item":"https://daily.dev/squads/scope_space"},{"@type":"ListItem","position":3,"name":"Row locking in SQLAlchemy"}]}
```

