2010-01-01 94 views
17

我正在Python中編寫一個小型的數據庫適配器,主要是爲了好玩。我試圖讓代碼從MySQL連接「消失」的情況中正常恢復,也就是wait_timeout被超出。我已經設置wait_timeout10,所以我可以試試這個。優雅地處理「MySQL已經消失」

這裏是我的代碼:

def select(self, query, params=[]): 
     try: 
      self.cursor = self.cxn.cursor() 
      self.cursor.execute(query, params) 
     except MySQLdb.OperationalError, e: 
      if e[0] == 2006: 
       print "We caught the exception properly!" 
       print self.cxn 
       self.cxn.close() 
       self.cxn = self.db._get_cxn() 
       self.cursor = self.cxn.cursor() 
       self.cursor.execute(query, params) 
       print self.cxn 

     return self.cursor.fetchall() 

接下來,我等待10秒鐘,並嘗試提出請求。以下是CherryPy的外觀:

[31/Dec/2009:20:47:29] ENGINE Bus STARTING 
[31/Dec/2009:20:47:29] ENGINE Starting database pool... 
[31/Dec/2009:20:47:29] ENGINE POOL Connecting to MySQL... 
[31/Dec/2009:20:47:29] ENGINE POOL Connecting to MySQL... 
[31/Dec/2009:20:47:29] ENGINE POOL Connecting to MySQL... 
[31/Dec/2009:20:47:29] ENGINE POOL Connecting to MySQL... 
[31/Dec/2009:20:47:29] ENGINE POOL Connecting to MySQL... 
[31/Dec/2009:20:47:29] ENGINE Started monitor thread '_TimeoutMonitor'. 
[31/Dec/2009:20:47:29] ENGINE Started monitor thread 'Autoreloader'. 
[31/Dec/2009:20:47:30] ENGINE Serving on 0.0.0.0:8888 
[31/Dec/2009:20:47:30] ENGINE Bus STARTED 
We caught the exception properly! <====================================== Aaarg! 
<_mysql.connection open to 'localhost' at 1ee22b0> 
[31/Dec/2009:20:48:25] HTTP Traceback (most recent call last): 
    File "/usr/local/lib/python2.6/dist-packages/CherryPy-3.1.2-py2.6.egg/cherrypy/_cprequest.py", line 606, in respond 
cherrypy.response.body = self.handler() 
    File "/usr/local/lib/python2.6/dist-packages/CherryPy-3.1.2-py2.6.egg/cherrypy/_cpdispatch.py", line 25, in __call__ 
    return self.callable(*self.args, **self.kwargs) 
    File "adp.py", line 69, in reports 
    page.sources = sql.GetSources() 
    File "/home/swoods/dev/adp/sql.py", line 45, in __call__ 
    return getattr(self.formatter.cxn, parsefn)(sql, sql_vars) 
    File "/home/swoods/dev/adp/database.py", line 96, in select 
    self.cursor.execute(query, params) 
    File "/usr/lib/pymodules/python2.6/MySQLdb/cursors.py", line 166, in execute 
    self.errorhandler(self, exc, value) 
    File "/usr/lib/pymodules/python2.6/MySQLdb/connections.py", line 35, in defaulterrorhandler 
    raise errorclass, errorvalue 
OperationalError: (2006, 'MySQL server has gone away') 

[31/Dec/2009:20:48:25] HTTP 
Request Headers: 
    COOKIE: session_id=e14f63acc306b26f14d966e606612642af2dd423 
    HOST: localhost:8888 
    CACHE-CONTROL: max-age=0 
    ACCEPT: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 
    ACCEPT-CHARSET: ISO-8859-1,utf-8;q=0.7,*;q=0.3 
    USER-AGENT: Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.5 (KHTML, like  Gecko) Chrome/4.0.249.43 Safari/532.5 
    CONNECTION: keep-alive 
    Remote-Addr: 127.0.0.1 
    ACCEPT-LANGUAGE: en-US,en;q=0.8 
    ACCEPT-ENCODING: gzip,deflate 
127.0.0.1 - - [31/Dec/2009:20:48:25] "GET /reports/1 HTTP/1.1" 500 1770 "" "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.43 Safari/532.5" 

爲什麼不工作?我清楚地捕捉到異常,重新生成連接和光標,但它仍然不起作用。它與MySQLdb如何獲得連接有關?

回答

12

從代碼中看不到,但我的猜測是db._get_cxn()方法正在做某種連接池並返回現有連接對象而不是創建新連接對象。是否沒有打電話給db來沖洗現有的無用連接? (你應該真的打電話給一個內部的_ - 前綴的方法?)

爲了防止MySQL has gone away我通常更喜歡保留一個時間戳與我最後一次使用它的連接。然後再嘗試再次使用它,我看看時間戳,並關閉/放棄連接,如果它是最近幾個小時以前使用的。這節省了用try...except OperationalError...try again包裝每一個可能的查詢。

+0

正確的你是在這兩個帳戶。這件事已經走向了許多不同的方向。我實際上實施了第2段的建議,這是我喜歡的做事方式。我已經重寫了代碼來修復你在第一段中提出的錯誤(錯誤就是這樣的......我是我自己重構的受害者)。 非常感謝您的幫助。新年快樂! – 2010-01-01 05:33:27

+5

@SeanWoods - 你能分享一下你正確的代碼嗎?我遭受同樣的問題,你做... – Jonathan 2011-10-20 09:56:29

+0

@SeanWoods你有沒有想過分享代碼的任何想法?看起來我也遭受同樣的錯誤。我已經在我的初始數據庫連接周圍放了一個while循環來進行3次嘗試,但正如bobince所提到的,除了每個查詢之外,我都試過了。我確實嘗試除了每一個查詢,但我沒有真正捕捉到服務器發生異常。 – 2013-03-23 16:25:32