Domanda

Sto usando SQLAlchemy come ORM all'interno di un'applicazione che sto costruendo da un po 'di tempo.

Finora, è stato un ORM abbastanza indolore da implementare e utilizzare, tuttavia, una recente funzionalità su cui sto lavorando richiede un persistente & amp; implementazione in stile coda distribuita (list & amp; worker), che ho creato in MySQL e Python.

Ha funzionato abbastanza bene fino a quando non l'ho testato in un ambiente ridimensionato. Ho usato il blocco a livello di riga di InnoDB per assicurarmi che ogni riga venga letta una sola volta, mentre la riga è bloccata, aggiorno un valore ' in_use ', per assicurarmi che altri non prendere alla voce.

Poiché MySQL non offre un " NOWAIT " metodo come Postgre o Oracle, ho riscontrato problemi di blocco in cui i thread di lavoro si bloccano e aspettano che la riga bloccata diventi disponibile.

Nel tentativo di superare questa limitazione, ho cercato di mettere tutta l'elaborazione necessaria in una singola istruzione ed eseguirla attraverso il metodo execute() dell'ORM , sebbene SQLAlchemy si rifiuti di restituire il risultato della query.

Ecco un esempio.

La mia istruzione SQL è:

SELECT id INTO @update_id FROM myTable WHERE in_use=0 ORDER BY id LIMIT 1 FOR UPDATE;
UPDATE myTable SET in_use=1 WHERE id=@update_id;
SELECT * FROM myTable WHERE id=@update_id;

Ed eseguo questo codice nella console:

engine = create_engine('mysql://<user details>@<server details>/myDatabase', pool_recycle=90, echo=True)
result = engine.execute(sqlStatement)
result.fetchall()

Solo per ottenere questo risultato

[]

Sono certo che l'istruzione sia in esecuzione poiché vedo che l'aggiornamento ha effetto nel database e, se eseguo tramite il terminale mysql o altri strumenti, ottengo la riga modificata restituita. Sembra solo essere SQLAlchemy che non vuole riconoscere la riga restituita.

Esiste qualcosa di specifico da fare per garantire che l'ORM raccolga la risposta?

Saluti

È stato utile?

Soluzione

Hai eseguito 3 query e MySQLdb crea un set di risultati per ciascuna. Devi recuperare il primo risultato, quindi chiamare cursor.nextset () , recuperare il secondo e così via.

Questo risponde alla tua domanda, ma non ti sarà utile, perché non risolverà il problema di blocco. Devi capire come FOR UPDATE funziona per primo: blocca le righe restituite fino alla fine della transazione. Per evitare un lungo blocco, devi renderlo il più breve possibile: SELEZIONA ... PER AGGIORNAMENTO , UPDATE SET in_use = 1 ... , COMMIT . In realtà non è necessario inserirli in una singola istruzione SQL, anche 3 chiamate execute () andranno bene. Ma devi impegnarti prima di un lungo calcolo, altrimenti il ??blocco verrà trattenuto troppo a lungo e l'aggiornamento in_use (blocco offline) non ha senso. E sicuramente puoi fare la stessa cosa anche usando ORM.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top