2010-01-01 5 views
17

J'écris un petit adaptateur de base de données en Python, surtout pour le plaisir. J'essaye d'obtenir le code pour récupérer gracieusement d'une situation où la connexion de MySQL "s'en va", aka wait_timeout est dépassée. J'ai mis wait_timeout à 10 donc je peux essayer cela.Manipulation gracieuse "MySQL est parti"

Voici mon code:

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

Ensuite, j'attends dix secondes et essayer de faire une demande. Voici à quoi ressemble 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" 

Pourquoi cela ne fonctionne-t-il pas? J'attrape clairement l'exception, régénérer à la fois la connexion et le curseur, mais ça ne marche toujours pas. Est-ce lié à la façon dont MySQLdb obtient les connexions?

Répondre

12

Impossible de voir à partir du code, mais je suppose que la méthode db._get_cxn() effectue une sorte de connexion de connexion et renvoie l'objet de connexion existant au lieu d'en créer un nouveau. N'y at-il pas un appel que vous pouvez faire sur db pour vider la connexion inutile existante? (Et devriez-vous vraiment appeler une méthode -prefixed interne?)

Pour prévenir MySQL has gone away Je préfère généralement garder un horodatage avec la connexion de la dernière fois que je l'ai utilisé. Ensuite, avant d'essayer de l'utiliser à nouveau, je regarde l'horodatage et ferme/rejette la connexion si elle a été utilisée pour la dernière fois il y a quelques heures. Cela économise envelopper chaque requête possible avec un try...except OperationalError...try again.

+0

Droit vous êtes sur les deux comptes. Cette chose est allée dans beaucoup de directions différentes. J'ai effectivement mis en œuvre la suggestion du paragraphe 2, et c'est ma façon préférée de faire les choses. J'ai réécrit le code pour corriger le bug que vous suggérez au paragraphe un (le bug était exactement cela ... Je suis victime de mon propre refactoring). Merci beaucoup pour votre aide. Bonne année! –

+5

@SeanWoods - Pourriez-vous partager votre code corrigé? Je souffre du même problème que vous ... – Jonathan

+0

@SeanWoods Avez-vous pensé à partager le code? On dirait que je souffre aussi de la même erreur. J'ai mis une boucle autour de ma connexion de base de données initiale pour 3 tentatives, mais comme Bobince mentionné, j'ai mis essayer sauf dans chaque requête. J'ai essayer, sauf pour chaque requête, mais je ne suis pas vraiment attraper serveur exception faite. –

Questions connexes