【问题标题】:Python/Django script crashes on MySQL deadlockPython/Django 脚本在 MySQL 死锁时崩溃
【发布时间】:2012-08-29 14:46:07
【问题描述】:

由于死锁,以下脚本和平保持错误:

sqlQuery = """INSERT INTO gps_points (gps_track_segment_id, gps_unit_id, date, lat,  lng) SELECT MAX(gps_track_segments.id) AS gps_track_segment_id, %(gps_unit_id)s AS gps_unit_id, %(date)s AS date, %(lat)s AS lat, %(lng)s AS lng FROM gps_track_segments 
    INNER JOIN gps_tracks ON gps_track_segments.gps_track_id = gps_tracks.id WHERE gps_tracks.hash = %(track)s"""

from django.db import connection, transaction
cursor = connection.cursor()
success = cursor.execute(sqlQuery, point)
transaction.commit_unless_managed()

错误日志显示:

2012-08-28 12:37:58,051 - django.db.backends - DEBUG - (0.018) INSERT INTO gps_points (gps_track_segment_id, gps_unit_id, date, lat, lng) SELECT MAX(gps_track_segments.id) AS gps_track_segment_id, 121 AS gps_unit_id, '2012-08-28 12:37:56' AS date, 51361100 AS lat, 4983910 AS lng FROM gps_track_segments 
    INNER JOIN gps_tracks ON gps_track_segments.gps_track_id = gps_tracks.id WHERE gps_tracks.hash = '7f5d950564786e182e175fb5d8e1b937528f85cc1ddabbee0d53859fb603ede3'; args={'gps_unit_id': 121L, 'lat': 51361100, 'date': '2012-08-28 12:37:56', 'course': None, 'track': u'7f5d950564786e182e175fb5d8e1b937528f85cc1ddabbee0d53859fb603ede3', 'speed': '0.0', 'lng': 4983910, 'segment': 5, 'altitude': None, 'accuracy': None}
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib64/python2.6/threading.py", line 532, in __bootstrap_inner
self.run()
  File "/usr/lib64/python2.6/threading.py", line 484, in run
self.__target(*self.__args, **self.__kwargs)
  ...
  ...
  File "/tcpserver/gpslibs.py", line 75, in saveGpsPoint
success = cursor.execute(sqlQuery, point)
  File "/usr/lib/python2.6/site-packages/django/db/backends/util.py", line 40, in execute
return self.cursor.execute(sql, params)
  File "/usr/lib/python2.6/site-packages/django/db/backends/mysql/base.py", line 114, in execute
return self.cursor.execute(query, args)
  File "/usr/lib64/python2.6/site-packages/MySQLdb/cursors.py", line 173, in execute
self.errorhandler(self, exc, value)
  File "/usr/lib64/python2.6/site-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
raise errorclass, errorvalue
DatabaseError: (1213, 'Deadlock found when trying to get lock; try restarting transaction')

使用 mysql 命令 SHOW ENGINE INNODB STATUS 我看到上面的查询与 php 网站请求的查询冲突。问题是有时 php-request 被回滚,有时 INSERT。最后一种情况导致脚本因死锁错误而停止。 由于更改所涉及的查询非常困难。我现在喜欢如果:

我能否以某种方式制作一个不会因死锁而失败并再次尝试的 Django/Python 脚本? Ofcouse 我并不真正关心 php 请求失败或回滚。从可用性的角度来看,这很容易处理。我确实关心后端脚本失败。这需要高于一切

【问题讨论】:

    标签: python mysql django deadlock


    【解决方案1】:

    我能否以某种方式制作一个不会失败的 Django/Python 脚本 死锁,然后再试一次?

    您可以捕获引发的异常DatabaseError,然后执行再次执行事务的逻辑(可能通过在插入行之前先获取表上的写锁)。

    try:
        success = cursor.execute(sqlQuery, point)
    except DatabaseError:
         # retry here
    

    理想情况下,您应该将其包装在可以再次调用的方法中。

    【讨论】:

    • 我想到了这一点,但我不确定脚本是否崩溃是因为我没有 try catch 语句还是因为死锁本身。如果我要重试(以您的示例为例),是否会发生变化,锁会不断堆积,甚至数据可能会被多次插入?
    • 脚本崩溃是因为你没有捕捉到异常;并且由于系统无法获得锁而引发异常。现在,如果您可以获得独占写入锁,那么它应该允许执行您的插入查询 - 这将防止引发异常(除非它导致另一个异常 - 这就是为什么您应该始终捕获异常,尤其是与外部系统交互时)。
    • 好的,我不太确定 transaction.commit_unless_managed() 对我有什么作用。我怎样才能得到一个写锁,如果它没有得到会发生什么?您能否在 except 循环中使用回滚做一个更详细的示例?我真的不知道如何制作一个本身不是无限循环的函数(以及“死锁”除了数据库之外的脚本?)
    • 这不起作用。捕捉是微不足道的,但你不能简单地“在这里重试”,因为事务处于失败状态,如果你重试,只会抛出不同的错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-21
    • 1970-01-01
    • 2015-03-27
    • 2017-05-01
    • 1970-01-01
    • 2022-06-21
    • 1970-01-01
    相关资源
    最近更新 更多