Python SQLAlchemy 中 with_for_update 行级锁用法详解

季宁
季宁
发布时间:2026-10-14| 4人浏览过
原创

本文介绍 Python SQLAlchemy 中 with_for_update 方法的使用,替代已废弃的 with_lockmode。通过 nowait、of 等参数控制锁行为,并说明 MySQL InnoDB 引擎下明确指定主键可实现行级锁,否则可能升级为表级锁。

SQLAlchemy 行级锁实现方式

在 SQLAlchemy 中,实现行级锁主要有两种方法:with_lockmode(self, mode) 和 with_for_update(self, read=False, nowait=False, of=None)。需要注意的是,前者已在 SQLAlchemy 0.9.0 版本中被标记为废弃,官方推荐使用后者 with_for_update 来替代。因此,在实际开发中应统一使用 with_for_update。

接下来我们查看该函数的具体定义及用法。

with_for_update 函数定义与参数


@_generative()
  def with_for_update(self, read=False, nowait=False, of=None):
    """return a new :class:`.Query` with the specified options for the
    ``FOR UPDATE`` clause.
 
    The behavior of this method is identical to that of
    :meth:`.SelectBase.with_for_update`. When called with no arguments,
    the resulting ``SELECT`` statement will have a ``FOR UPDATE`` clause
    appended. When additional arguments are specified, backend-specific
    options such as ``FOR UPDATE NOWAIT`` or ``LOCK IN SHARE MODE``
    can take effect.
 
    E.g.::
 
      q = sess.query(User).with_for_update(nowait=True, of=User)
 
    The above query on a Postgresql backend will render like::
 
      SELECT users.id AS users_id FROM users FOR UPDATE OF users NOWAIT
 
    .. versionadded:: 0.9.0 :meth:`.Query.with_for_update` supersedes
      the :meth:`.Query.with_lockmode` method.
 
    .. seealso::
 
      :meth:`.GenerativeSelect.with_for_update` - Core level method with
      full argument and behavioral description.
 
    """
     
read
  是标识加互斥锁还是共享锁. 当为 True 时, 即 for share 的语句, 是共享锁. 多个事务可以获取共享锁, 互斥锁只能一个事务获取. 有"多个地方"都希望是"这段时间我获取的数据不能被修改, 我也不会改", 那么只能使用共享锁.
nowait
  其它事务碰到锁, 是否不等待直接"报错".
of
  指明上锁的表, 如果不指明, 则查询中涉及的所有表(行)都会加锁.

示例代码如下: q = sess.query(User).with_for_update(nowait=True, of=User)

上述代码在支持的数据库后端(如 PostgreSQL)中,会生成对应的 SQL 语句。

生成的 SQL 如下: SELECT users.id AS users_id FROM users FOR UPDATE OF users NOWAIT

MySQL 下的锁行为差异

需要注意的是,MySQL 数据库并不支持 nowait 和 of 等特定参数。因此,在 MySQL 环境下,无论是否传递这些参数,最终转换生成的 SQL 语句均为:

SELECT users.id AS users_id FROM users FOR UPDATE

以下是一个完整的 Python 代码示例。

代码示例与输出结果


def query_city_for_update():
  session = get_session()
  with session.begin():
    query = session.query(City).with_for_update().filter(City.ID == 8)
    print 'SQL : %s' % str(query)
    print_city_info(query.first())

运行上述代码后,控制台输出的结果如下。


SQL : SELECT city."ID" AS "city_ID", city."Name" AS "city_Name", city."CountryCode" AS "city_CountryCode", city."District" AS "city_District", city."Population" AS "city_Population" 
FROM city 
WHERE city."ID" = :ID_1 FOR UPDATE

{'city': {'population': 234323, 'district': u'Utrecht', 'id': 8, 'country_code': u'NLD', 'name': u'Utrecht'}}

使用 SELECT ... FOR UPDATE 时,锁定的数据范围是关键注意事项。由于 MySQL 的 InnoDB 引擎默认采用行级锁(Row-Level Lock),只有当查询条件中明确指定了主键时,MySQL 才会执行行级锁,即仅锁定被选取的数据行。如果未明确指定主键,MySQL 可能会执行表级锁(Table Lock),导致整个数据表单被锁定。

以上内容涵盖了 SQLAlchemy 中 with_for_update 的核心用法及 MySQL 下的锁机制差异,希望对读者有所帮助。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。