题
我正在使用SQLAlchemy作为我已经构建了一段时间的应用程序中的ORM。
到目前为止,实现和使用它是一个相当轻松的ORM,但是,我正在研究的最新功能需要持久的<!>放大器;分布式队列(list <!> amp; worker)样式实现,我在MySQL和Python中构建。
直到我在一个缩放的环境中测试它之前,它们都运行良好。
我已经使用InnoDB行级锁定来确保每行只读一次,而行被锁定,我更新' in_use
'值,以确保其他人不抓住条目。
由于MySQL不提供<!>“NOWAIT <!>”;像Postgre或Oracle那样的方法,我遇到了工作线程挂起并等待锁定行可用的锁定问题。
为了克服这个限制,我试图将所有必需的处理放到一个语句中,并通过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获得响应?
干杯
解决方案
您已执行3次查询,MySQLdb为每个查询创建结果集。您必须获取第一个结果,然后调用cursor.nextset()
,获取秒,依此类推。
这回答了你的问题,但对你没用,因为它不会解决锁定问题。您必须先了解FOR UPDATE的工作原理:它会将返回的行锁定到事务结束。为了避免长时间锁定等待,您必须尽可能缩短时间:SELECT ... FOR UPDATE
,UPDATE SET in_use=1 ...
,COMMIT
。实际上你不需要将它们放入单个SQL语句中,3 execute()
调用也可以。但是你必须在长时间计算之前提交,否则锁定将保持太长时间并且更新in_use
(离线锁定)毫无意义。并且确定你也可以使用ORM做同样的事情。