Python 为更新查询选择:超过锁定等待超时错误

Python 为更新查询选择:超过锁定等待超时错误,python,mysql,django,select,locking,Python,Mysql,Django,Select,Locking,为了避免争用条件,我需要在查询数据库时使用select for update功能,以便在事务结束前锁定行。由于Django 1.3中不存在select_for_update查询,因此我使用了一个类方法来解决这个问题,该类方法通过执行原始sql查询返回查询集 #models.py class AccountDetails(models.Model): user = models.OneToOneField(User) amount = models.IntegerField(max

为了避免争用条件,我需要在查询数据库时使用
select for update
功能,以便在事务结束前锁定行。由于Django 1.3中不存在select_for_update查询,因此我使用了一个类方法来解决这个问题,该类方法通过执行原始sql查询返回查询集

#models.py
class AccountDetails(models.Model):
    user = models.OneToOneField(User)
    amount = models.IntegerField(max_length=15,null=True,blank=True)

    @classmethod
    def get_locked_for_update(cls,userid):
        accounts = cls.objects.raw("SELECT * FROM b2b_accountdetails WHERE user_id ="+str(userid)+" FOR UPDATE")
        return accounts[0]
这就是它在视图中的使用方式

account = AccountDetails.get_locked_for_update(userid)
account.amount = account.amount - fare
account.save()
在最后一行,我得到了这个错误:
操作错误:(1205,‘超过锁定等待超时;尝试重新启动事务’

在dbshell中,运行
save()
行后:

mysql> SHOW FULL PROCESSLIST;
+-----+------+-----------+-----------+---------+------+----------+-----------------------------------------------------------------------------------------------------+
| Id  | User | Host      | db     | Command | Time | State    | Info                                                                                                |
+-----+------+-----------+-----------+---------+------+----------+--------------------------    ---------------------------------------------------------------------------+
|  51 | root | localhost | dbname | Query   |    0 | NULL     | SHOW FULL PROCESSLIST                                                                               |
| 767 | root | localhost | dbname | Sleep   |   59 |          | NULL                                                                                                |
| 768 | root | localhost | dbname | Query   |   49 | Updating | UPDATE `b2b_accountdetails` SET `user_id` = 1, `amount` = 68906 WHERE `appname_accountdetails`.`id` = 1 |
+-----+------+-----------+-----------+---------+------+----------+--------------------------    ---------------------------------------------------------------------------+
根据我的理解,锁应该在第一次数据更改查询时释放,如更新、删除等

但是
save()
语句被阻止并一直处于等待状态。知道为什么会这样吗?我的想法是,当我调用
account.save()
时,它不会拾取由select for update查询启动的上一个事务


我错过了什么明显的东西吗?请提供帮助。

将Django保留为此类操作的默认自动提交行为很容易导致多种错误(根本不锁定数据库可能是另一种结果);详细信息可能取决于特定RDBMS的RDBMS和/或Django数据库驱动程序。最好使用。

将Django保留为其默认的类似自动提交的行为,这样的操作很容易导致多种错误(根本不锁定数据库可能是另一种结果);详细信息可能取决于特定RDBMS的RDBMS和/或Django数据库驱动程序。使用它会更好。

我认为其他线程在某个记录上持有记录锁的时间太长,并且您的线程正在超时。这是MYSQL特有的问题,它不支持nowait


您可以为innodb\u lock\u wait\u timeout设置更高的值,然后重新启动mysql

我认为其他线程在某些记录上持有记录锁的时间太长,而您的线程正在超时这是mysql特有的问题,它不支持nowait


您可以为
innodb\u lock\u wait\u timeout设置更高的值,然后重新启动mysql

您是否使用TransactionMiddleware?这个问题是否发生在HTTP请求的上下文中?@AntonisChristofides否我没有使用TransactionMiddleware。是的,它发生在HTTP请求的上下文中,但不仅仅发生在HTTP请求的上下文中。当我从django shell运行代码时也会出现同样的错误。您是否使用TransactionMiddleware?这个问题是否发生在HTTP请求的上下文中?@AntonisChristofides否我没有使用TransactionMiddleware。是的,它发生在HTTP请求的上下文中,但不仅仅发生在HTTP请求的上下文中。当我从django shell运行代码时也会出现同样的错误。不,我认为我可以安全地排除任何其他线程持有记录的可能性。因为即使我杀死
SHOW FULL PROCESSLIST中显示的所有线程出现此问题。然而,这个调试证实了我最初的猜测:我的select查询和update查询在两个不同的线程上运行。我将在我的问题中更新这个发现。不,我认为我可以安全地排除任何其他线程持有记录的可能性。因为即使我杀死
SHOW FULL PROCESSLIST中显示的所有线程出现此问题。然而,这个调试证实了我最初的猜测:我的select查询和update查询在两个不同的线程上运行。我将在我的问题中更新这个发现。我尝试了两种方法,但都不起作用。请看我更新的问题。执行
account.save()
操作时,将创建一个新线程。因此它被阻止,因为上一个线程已经锁定了该行。只是为了确定:您试图手动修改包含
account.save()
的函数。是的,我将部分从选择查询移动到另一个函数以保存,并仅对该函数而不是视图应用了decorator。我尝试了这两种方法,但它不起作用。请看我更新的问题。执行
account.save()
操作时,将创建一个新线程。因此,它被阻止,因为上一个线程已经锁定了该行。只是为了确定:您尝试手动修改包含
account.save()
的函数。是的,我将部分从选择查询移动到另一个函数以保存,并仅在该函数上应用了decorator,而不是在视图上应用了decorator。