2012-08-29 19 views
2

腳本中的和平與錯誤認爲由於死鎖:的Python/Django的腳本對MySQL的僵局崩潰

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請求失敗或獲得回滾。從可用性的角度來看,處理這個很容易。我關心後端腳本失敗。這需要工作高於一切

回答

2

我可以以某種方式使一個Django/Python腳本不會失敗的 死鎖,只是再次嘗試?

您可以捕獲該異常升高DatabaseError,然後執行你的再次執行該交易的邏輯(可能通過收購在桌子上寫鎖定插入行的第一個前)。

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

你應該最好把它包裝在一個你可以再次調用的方法中。

+0

我想到了這一點,但我不確定腳本是否崩潰,因爲我沒有try catch語句或因爲死鎖本身。如果我要重試(在你的例子中),是不是有變化,鎖繼續堆積,甚至可能多次插入數據? – Jeroen

+0

腳本崩潰,因爲您沒有捕捉異常;並且由於系統無法鎖定而引發異常。現在,如果你可以得到一個_exclusive寫入鎖_,那麼它應該允許你的插入查詢被執行 - 這將防止異常被引發(除非它引起另一個異常 - 這就是爲什麼你總是應該捕獲異常,特別是當與外部系統)。 –

+0

好吧,我不確定什麼transaction.commit_unless_managed() 對我來說。我怎樣才能得到一個寫鎖定,如果它沒有得到一個,會發生什麼?你可以在except循環中做一個更復雜的回滾示例嗎?我真的不知道如何創建一個本身不是無限循環的函數(並且除了數據庫之外「死鎖」腳本?) – Jeroen