2010-01-01 8 views
17

Escribo un pequeño adaptador de base de datos en Python, principalmente por diversión. Intento que el código se recupere con gracia de una situación en la que la conexión MySQL "se va", se excede wait_timeout. Establecí wait_timeout en 10, así que puedo intentarlo.Manejo elegante de "MySQL se ha ido"

Aquí está mi código:

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

siguiente que esperar diez segundos y tratar de hacer una petición. Esto es lo que parece 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" 

¿Por qué no funciona? Claramente atrapo la excepción, regenero tanto la conexión como el cursor, pero todavía no funciona. ¿Está relacionado con la forma en que MySQLdb obtiene las conexiones?

Respuesta

12

No se puede ver desde el código, pero supongo que el método db._get_cxn() está realizando una especie de agrupación de conexiones y devuelve el objeto de conexión existente en lugar de crear uno nuevo. ¿No hay una llamada que puede hacer en db para purgar la conexión inútil existente? (¿Y debería estar llamando a un método interno _ -prefixed?)

Para prevenir MySQL has gone away Por lo general, prefiero mantener una marca de tiempo con la conexión de la última vez que lo usé. Luego, antes de volver a utilizarlo, miro la marca de tiempo y cierro/descarto la conexión si fue utilizada por última vez hace unas horas. Esto ahorra envolver todas las consultas posibles con un try...except OperationalError...try again.

+0

Derecho en ambas cuentas. Esto ha ido en diferentes direcciones. De hecho, implementé la sugerencia del párrafo 2 y es mi manera preferida de hacer las cosas. He reescrito el código para corregir el error que sugieres en el primer párrafo (el error fue exactamente eso ... Soy víctima de mi propia refactorización). Muchas gracias por su ayuda. ¡Feliz año nuevo! –

+5

@SeanWoods - ¿Podría compartir su código corregido? Estoy sufriendo el mismo problema que tu ... – Jonathan

+0

@SeanWoods ¿Has pensado en compartir el código? Parece que también estoy sufriendo el mismo error. He puesto un ciclo while alrededor de mi conexión de base de datos inicial durante 3 intentos, pero como mencioné bobince lo he intentado, excepto en cada consulta. Lo intento, excepto para cada consulta, pero no estoy realmente atrapado en el servidor. –

Cuestiones relacionadas