2011-10-13 3 views
6

Ho scritto un demone python che esegue il polling continuo di un database mysql. Funziona bene quando ho continuamente collegare e riconnettersi al database tra le query come segue:Python MySQLdb vuota la query di selezione anche se l'esecuzione manuale della query fornisce risultati

def connect(self): 
    self.connection = MySQLdb.connect(...) 
    self.cursor = self.connection.cursor() 
    return self.cursor 

def disconnect(self): ... 
    self.cursor.close() 
    self.connection.close() 

def getData(); .... 
    sqlcmd = """SELECT ....""" 
    self.cursor.execute (sqlcmd % (params)) 
    result = self.cursor.fetchall() 
    return result 

if __name__ == "__main__": 
    db = prepaid_db.Database() 
    while 1: 
     dbConnection = db.connect() 
     data = db.getData() 
     ... do stuff 
     db.disconnect 

Ma quando cerco di mantenere la connessione al database aperto (come sotto) ottengo una query vuota, anche se, mentre è eseguendo posso interrogare il db manualmente, dargli la stessa query e ottenere il risultato che mi aspetto.

if __name__ == "__main__": 
    db = prepaid_db.Database() 
    dbConnection = db.connect() 
    while 1: 
     data = db.getData() 
     ... do stuff 
    db.disconnect 

Ho provato di tutto per capire il motivo per cui avrebbe fatto questo:

  • la cache disabilitata interrogazione

    e ha aggiunto casuali x = x alla query nella cache caso MySQL è stato confuso dalle query simili
  • abilitata la registrazione delle query mysql: la query arriva ma restituisce ancora un set vuoto
  • spostato cursor.connect in database.connect e di nuovo in getData(), nessuna differenza

Mi piacerebbe un indizio su cosa non sto capendo.

+0

Il punto e virgola in 'def getData();' deve essere due punti. – unutbu

+0

'self.cursor.fetchall()' restituisce 'None' la prima volta attraverso il' while-loop', o dopo molti passaggi? – unutbu

+0

- sì sul colon, mi spiace, semplice errore di battitura –

risposta

6

Probabilmente stai interrogando una tabella InnoDB in cui un altro processo inserisce nuovi dati nel frattempo. In questo caso, il server MySQL avvia automaticamente una nuova transazione per la tua connessione, e dal momento che non chiami dbConnection.commit() o .rollback() ovunque, sei bloccato per sempre in quella transazione. Le impostazioni predefinite di InnoDB assicurano che ogni volta che esegui query sui dati, vedrai sempre lo stesso risultato all'interno di una transazione. Quindi qualunque sia l'altro processo che sta inserendo nella tabella è nascosto dalla connessione del demone.

La soluzione è semplice: anziché chiamare db.disconnect(), chiamare dbConnection.commit(), che termina la corrente e avvia una nuova transazione.

+3

geni là fuori! –

+0

grazie Simon, era l'unica tabella InnoDB nel mio DB e non pensavo che avrebbe avuto un impatto su un'istruzione Select. Ma chiaramente lo fa, ho aggiunto il commit() e ora funziona perfettamente! Grazie mille! –

+0

maaaaaaaan! è stato fantastico, pensavo che db.commit() fosse solo per l'aggiornamento. Questo mi ha salvato la vita. – AliBZ

2

L'oggetto MySQLdb.cursor probabilmente non supporta il commit come indicato in MySQLDB manual. Gli oggetti di connessione, d'altra parte, lo fanno.

Poiché gestisci tutto attraverso la classe Database, immagino che il codice di commit possa andare lì.

solo per dare un codice per quello che Simon ha detto

def connect(self): 
     self.connection = MySQLdb.connect(...) 
     self.cursor = self.connection.cursor() 

    def disconnect(self): ... 
     self.cursor.close() 
     self.connection.commit() 
     self.connection.close() 

    def commit(self): 
     self.connection.commit() 

    def getData(self): .... 
     sqlcmd = """SELECT ....""" 
     self.cursor.execute (sqlcmd % (params)) 
     result = self.cursor.fetchall() 
     return result 

if __name__ == "__main__": 
    db = prepaid_db.Database() 
    db.connect() 
    while 1: 
     data = db.getData() 
     ... do stuff 
     db.commit() 
    db.disconnect() 

non sono sicuro, ma probabilmente si può anche fare qualcosa di simile

db.connection.commit() 

nel ciclo while invece di chiamare la nuova funzione definita

+0

grazie RebBaron, è esattamente come l'avevo fatto. –