\n我正在处理 PostgreSQL 中的一个我不明白的死锁问题。
\n我正在尝试使用 Python、psycopg2 模块和 Postgres 数据库实现类似循环的算法。
\n我希望应用程序的多个实例执行以下操作:
\n - 在很短的时间间隔内使用任务列表锁定整个表
\n - 选择要执行的任务(最近最少执行的任务,有一些限制)
\n - 标记任务,以便其他实例不选择它(仅允许一个实例同时执行同一任务)
\n - 解锁表
\n - 执行任务
\n - 重复
\n其他会话也应该能够更新某些任务该表的字段。
\n突然间,我陷入了无法解释的僵局。我已经尽可能地简化了我的Python脚本,我在每条语句之后执行提交(如果可能的话),但仍然时不时地出现死锁。
\n由于某种原因,每次出现死锁时,都是事务中的第一个语句。这怎么可能呢?我的表\xe2\x80\x99没有任何触发器、外键约束或任何会使事情变得复杂的东西。我能想到的唯一解释是 PostgreSQL 不会在提交后立即释放锁。或者也许是 psycopg2 没有按照我期望的方式工作?我无法通过在不同会话中手动运行语句来重现该问题。
\n死锁很少见,但我每隔几个小时至少会遇到一次
我在 PostgreSQL 9.6.1 和 Python 2.7.12 上运行
\n\n这是我运行的代码(这只是我为了解决问题而制作的简化示例):
\n\nimport psycopg2\nimport sys\nimport datetime\nimport time\nsys.path.append(\'/opt/workflow/lib\')\nimport config\nimport ovs_lib\n\n\ninstance_type=\'scan_master\'\ninstance_id=sys.argv[1]\n\ndbh=psycopg2.connect(dbname=config.values[\'pgsql\'][\'db\'], host=config.values[\'pgsql\'][\'host\'], port=int(config.values[\'pgsql\'][\'port\']), user=config.values[\'pgsql\'][\'user\'], password=config.values[\'pgsql\'][\'pass\'])\ndbh.set_session(isolation_level=\'READ COMMITTED\', autocommit=False)\ncursor = dbh.cursor()\ncursor.execute("SET search_path TO "+config.values[\'pgsql\'][\'schema\'])\n\ndef sanitize(string):\n string=string.replace("\'","\'\'")\n return string\n\ndef get_task(instance_id):\n task_id=None\n out_struct={}\n instance_id=sanitize(instance_id)\n #Lock whole table\n dbh.commit() #Just in case\n cursor.execute("SELECT …
Run Code Online (Sandbox Code Playgroud)