2011-11-09 14 views
12

Sono abituato a (rovinato da?) L'interfaccia SQLite di python per gestire i database SQL. Una caratteristica interessante nell'API di SQLite di Python è il "gestore di contesto", cioè la dichiarazione with di python. Io di solito eseguire le query nel modo seguente:Gestore del contesto per MySQLdb Python

import as sqlite 

with sqlite.connect(db_filename) as conn: 
    query = "INSERT OR IGNORE INTO shapes VALUES (?,?);" 
    results = conn.execute(query, ("ID1","triangle")) 

Con il codice di cui sopra, se la mia interrogazione modifica il database e mi dimentico di eseguire conn.commit(), il manager contesto corre per me automaticamente all'uscita dalla dichiarazione with. Gestisce bene anche le eccezioni: se si verifica un'eccezione prima che io commetta qualcosa, il database viene ripristinato.

Attualmente sto usando l'interfaccia MySQLdb, che non sembra supportare un gestore di contesto simile fuori dalla scatola. Come creo il mio? C'è una domanda correlata here, ma non offre una soluzione completa.

risposta

15

Si noti che le connessioni MySQLdb sono già ora gestori di contesto. Vedi user2966041's answer.


Si potrebbe usare qualcosa di simile:

import config 
import MySQLdb 
import MySQLdb.cursors as mc 
import _mysql_exceptions 
DictCursor = mc.DictCursor 
SSCursor = mc.SSCursor 
SSDictCursor = mc.SSDictCursor 
Cursor = mc.Cursor 


class Cursor(object): 
    def __init__(self, 
       cursorclass=Cursor, 
       host=config.HOST, user=config.USER, 
       passwd=config.PASS, dbname=config.MYDB, 
       driver=MySQLdb, 
       ): 
     self.cursorclass = cursorclass 
     self.host = host 
     self.user = user 
     self.passwd = passwd 
     self.dbname = dbname 
     self.driver = driver 
     self.connection = self.driver.connect(
      host=host, user=user, passwd=passwd, db=dbname, 
      cursorclass=cursorclass) 
     self.cursor = self.connection.cursor() 

    def __iter__(self): 
     for item in self.cursor: 
      yield item 

    def __enter__(self): 
     return self.cursor 

    def __exit__(self, ext_type, exc_value, traceback): 
     self.cursor.close() 
     if isinstance(exc_value, Exception): 
      self.connection.rollback() 
     else: 
      self.connection.commit() 
     self.connection.close() 

with Cursor() as cursor: 
    print(cursor) 
    connection = (cursor.connection) 
    print(connection) 

di usarlo si sarebbe posto config.py nel PYTHONPATH e definire il HOST, USER, PASS, variabili MYDB lì.

Si noti inoltre che oursql è un driver alternativo per MySQL che viene fornito con il with costrutto costruito in:

with some_connection as cursor: 
    do_something_with(cursor) 

Si potrebbe voler considerare l'utilizzo oursql invece.

+0

Ottima soluzione! Non solo hai dato la risposta per MySQLdb, ma può anche essere utilizzato con altri driver. Inoltre, oursql sembra promettente. Grazie. – conradlee

+0

@MMartins: Grazie mille per la correzione. – unutbu

17

Pensa che le cose sono cambiate da quando questa domanda è stata inizialmente posta. Abbastanza confusamente (almeno dal mio punto di vista), per le versioni recenti di MySQLdb, se si utilizza una connessione in un contesto si ottiene un cursore (come per l'esempio oursql), non qualcosa che si chiude automaticamente (come si farebbe se si aprisse un file per esempio).

Ecco quello che faccio:

from contextlib import closing 
with closing(getConnection()) as conn: #ensure that the connection is closed 
    with conn as cursor:    #cursor will now auto-commit 
     cursor.execute('SELECT * FROM tablename') 
+0

Auto commit? Come in, modalità di commit automatico, quindi non hai transazioni? – Halfgaar

Problemi correlati