我正在使用SQLAlchemy作为我已经构建了一段时间的应用程序中的ORM。
到目前为止,实现和使用它是一个相当轻松的ORM,但是,我正在开发的一个最近的功能需要持久的&分布式队列(list& worker)样式实现,我在MySQL和Python中构建。
直到我在一个缩放的环境中测试它之前,它们都运行良好。
我已经使用InnoDB行级锁定来确保每行只读一次,而行被锁定,我更新' in_use
'值,以确保其他行不抓住入口。
由于MySQL不像Postgre或Oracle那样提供“NOWAIT”方法,因此我遇到了工作线程挂起并等待锁定行变为可用的锁定问题。
为了克服这个限制,我尝试将所有必需的处理放在一个语句中,并通过ORM的 execute()
方法运行它,尽管SQLAlchemy是拒绝返回查询结果。
这是一个例子。
我的SQL语句是:
SELECT id INTO @update_id FROM myTable WHERE in_use=0 ORDER BY id LIMIT 1 FOR UPDATE;
UPDATE myTable SET in_use=1 WHERE id=@update_id;
SELECT * FROM myTable WHERE id=@update_id;
我在控制台中运行此代码:
engine = create_engine('mysql://<user details>@<server details>/myDatabase', pool_recycle=90, echo=True)
result = engine.execute(sqlStatement)
result.fetchall()
仅获得此结果
[]
我确定该语句正在运行,因为我可以看到更新在数据库中生效,如果我通过mysql终端或其他工具执行,我会返回修改后的行。 它似乎只是SQLAlchemy不想确认返回的行。
是否需要采取任何具体措施来确保ORM获得响应?
干杯
答案 0 :(得分:3)
您已执行3次查询,MySQLdb为每个查询创建结果集。您必须获取第一个结果,然后调用cursor.nextset()
,获取秒,依此类推。
这回答了你的问题,但对你没用,因为它不会解决锁定问题。您必须先了解FOR UPDATE的工作原理:它会将返回的行锁定到事务结束。为避免长时间锁定等待,您必须尽可能缩短时间:SELECT ... FOR UPDATE
,UPDATE SET in_use=1 ...
,COMMIT
。实际上你不需要将它们放入单个SQL语句中,3 execute()
个调用也可以。但是你必须在长时间计算之前提交,否则锁将保持太长时间并且更新in_use
(离线锁定)是没有意义的。并且确定你也可以使用ORM做同样的事情。