我对sqlalchemy-psql中的锁定机制如何工作完全感到困惑。 我正在运行一个带有sqlalchemy和postgres的python-flask应用程序。由于我有多个线程处理一些数据并在psql上更新它,我得到以下死锁:
2015-12-31 17:[ERROR](由于Query-invoked autoflush引发;考虑使用session.no_autoflush阻止,如果此刷新过早发生)(psycopg2.extensions.TransactionRollbackError)检测到死锁
详细信息:进程22833在事务14114188上等待ShareLock;被进程阻止19759。
流程19759在交易14114189上等待ShareLock;被程序22833阻止。
这是否会出现僵局:
Thread 1 Thread 2
| (start an sqlalchemy session) |
db.session() db.session()
|(Using sqlalchemy) |
Update row1 of table1 Update row2 of table 1
| |
Update row2 of table1 Update row1 of table1
| |
session.commit() session.commit()
Here是我的问题的一些答案,但我无法将它们与sqlalchemy联系起来。
答案 0 :(得分:3)
在PostgreSQL中,行会在更新时被锁定 - 实际上,这实际上的工作方式是每个元组(行的版本)都有一个名为xmin的系统字段,用于指示哪个事务使该元组成为当前(通过插入或更新)和一个名为xmax的系统字段,以指示哪个事务已过期该元组(通过更新或删除)。当您访问数据时,它会检查每个元组,以确定您的事务是否可见,方法是根据这些值检查您的活动“快照”。
如果您正在执行UPDATE并且与您的搜索条件匹配的元组具有xmin,这将使您的快照和活动事务的xmax可见,它将阻塞,等待该事务完成。如果首次更新元组的事务回滚,则事务会唤醒并处理该行;如果第一个事务提交,则事务会唤醒并根据当前事务隔离级别采取操作。
显然,死锁是以不同顺序发生在行中的结果。 RAM中没有行级锁定,可以同时为所有行获取,但如果行以相同的顺序更新,则无法进行循环锁定。不幸的是,建议的IN(1,2)语法并不能保证这一点。不同的会话可能有不同的成本因素活动,后台“分析”任务可能会更改一个计划的生成与另一个计划之间的表的统计信息,或者它可能正在使用seqscan并受PostgreSQL优化的影响,导致新的seqscan加入一个已在进行中并“循环”以减少磁盘I / O.
读这个 http://elioxman.blogspot.in/2013/02/postgres-deadlock.html