Python中sqlalchemy使用乐观锁时如何获取更新行数或判断更新成功?
我理解 sqlalchemy 在事务中,update 不会立刻生效,甚至不会立刻发到服务器上,而是等到 commit 才生效。
举个例子:
with Seesion as session:
object = session.query(Table).where(key=param).limit(1)
content = "这里是业务逻辑计算的值"
# 用取到的对象的 ID 进行更新,只有一个线程能更新成功,我理解
Table.update(Table).set(Table.content = content).where(id = object.id)
sessoin.commit()
那么问题来了,如果我想知道我 update 操作(或者说是 commit 操作)是否成功(影响了一行)该怎么办呢? 因为可能还有一些后续操作,需要确认更新成功,拿到锁才能继续
Python中sqlalchemy使用乐观锁时如何获取更新行数或判断更新成功?
6 回复
很长时间没用 python 了,
update 返回值应该是实际更新的函数。
在SQLAlchemy里用乐观锁,更新后想拿到影响的行数或者判断是否成功,直接看session.execute()返回的ResultProxy对象的rowcount属性就行。
核心就这几步:
- 在模型里加个
version_id字段,用Column(Integer, default=0)定义。 - 在类里设置
__mapper_args__ = {"version_id_col": Model.version_id}。 - 更新时正常操作,但执行后会检查版本号。如果版本对不上(别人先改了),SQLAlchemy会抛
StaleDataError异常。 - 没异常的话,
result.rowcount就是实际更新的行数。通常乐观锁更新成功时,这个值应该是1(因为你只更新了符合版本条件的那一行)。
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.orm import declarative_base, sessionmaker
from sqlalchemy.exc import StaleDataError
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
version_id = Column(Integer, default=0) # 乐观锁字段
__mapper_args__ = {
"version_id_col": version_id
}
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
# 添加测试数据
user = User(name='Alice')
session.add(user)
session.commit()
# 模拟并发更新
session1 = Session()
user1 = session1.query(User).first()
user1.name = 'Alice Updated'
session2 = Session()
user2 = session2.query(User).first()
user2.name = 'Bob'
session2.commit() # 先提交一个更新
try:
result = session1.execute(
session1.query(User).filter(User.id == user1.id).update(
{'name': user1.name}
)
)
session1.commit()
print(f"更新行数: {result.rowcount}")
if result.rowcount == 1:
print("更新成功")
else:
print("更新失败,可能是版本冲突")
except StaleDataError:
print("乐观锁冲突:数据已被其他事务修改")
简单说就是:用rowcount看更新行数,抓到StaleDataError就是版本冲突更新失败。
如果 update 或 commit 不成功,会直接抛出异常吧。
拿到锁才能继续是什么意思?
- 你这没有乐观锁
2. update 没在事务中
3. ResultProxy.rowcount 是更新的行数
query= session.query(Table).where(key=param).limit(1)
with session.begin():
____query.update({key: value})
____session.commt()
这样写才是事务
#3 感谢。
第二点确实是我写范例代码时候疏忽了

