2010-01-01 15 views
17

Sto scrivendo un piccolo adattatore per database in Python, principalmente per divertimento. Sto cercando di ottenere il codice per ripristinare con garbo da una situazione in cui la connessione MySQL "va via", alias wait_timeout viene superata. Ho impostato wait_timeout allo 10, quindi posso provarlo.Gestire con garbo "MySQL è andato via"

Ecco il mio codice:

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() 

Avanti Aspetto dieci secondi e cercare di fare una richiesta. Ecco come appare 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" 

Perché non funziona ?? Rilevo chiaramente l'eccezione, rigenera sia la connessione che il cursore, ma non funziona ancora. È legato a come MySQLdb ottiene le connessioni?

risposta

12

Impossibile vedere dal codice, ma suppongo che il metodo db._get_cxn() stia eseguendo un qualche tipo di pool di connessioni e restituisca l'oggetto di connessione esistente invece di crearne uno nuovo. Non c'è una chiamata che puoi effettuare su db per svuotare la connessione inutile esistente? (E dovresti davvero chiamare un metodo interno _ -prefixed?)

Per prevenire MySQL has gone away Generalmente preferisco tenere un timestamp con la connessione dell'ultima volta che l'ho usato. Quindi, prima di provare ad usarlo di nuovo, osservo il timestamp e chiudo/scarto la connessione se è stata usata l'ultima volta più di qualche ora fa. Ciò consente di salvare l'involucro di ogni query possibile con uno try...except OperationalError...try again.

+0

Proprio su entrambi i conti. Questa cosa è andata in molte direzioni diverse. In realtà ho implementato il suggerimento del paragrafo 2, ed è il mio modo preferito di fare le cose. Ho riscritto il codice per correggere l'errore suggerito nel primo paragrafo (il bug era esattamente quello ... Sono vittima del mio refactoring). Grazie mille per il vostro aiuto. Felice anno nuovo! –

+5

@SeanWoods - Potresti condividere il tuo codice corretto? Sto soffrendo dello stesso problema che hai avuto ... – Jonathan

+0

@SeanWoods Hai mai pensato di condividere il codice? Sembra che anch'io soffra dello stesso errore. Ho messo un ciclo while attorno alla mia connessione al database iniziale per 3 tentativi ma, come menzionato da bobince, ho provato, tranne in ogni singola query. Devo provare ad eccezione di ogni singola query, ma non sto davvero prendendo l'eccezione del server andato. –

Problemi correlati