2009-06-30 20 views
15

Come si dovrebbe garantire la correttezza quando più processi accedono a un singolo file di database SQLite?SQLite3 e più processi

+0

Almeno avresti potuto taggare la tua domanda con il linguaggio di programmazione appropriato. –

+0

Yeap o specifica che è necessario un approccio agnostico indipendente dalla piattaforma indipendente dalla lingua. – sharptooth

+1

Vorrei provare a chiedere di nuovo senza "mostrami il codice" ... –

risposta

13

Innanzitutto, evitare l'accesso simultaneo ai file di database sqlite. La concorrenza è uno dei punti deboli di sqlite e se si dispone di un'applicazione molto concorrente, prendere in considerazione l'utilizzo di un altro motore di database.

Se non è possibile evitare la concorrenza o far cadere SQLite, avvolgere il vostro scrittura transazioni in BEGIN IMMEDIATE; ... END;. La modalità di transazione predefinita in sqlite è DEFERRED, il che significa che un blocco viene acquisito solo al primo tentativo di scrittura effettivo. Con le transazioni IMMEDIATE, il blocco viene acquisito immediatamente oppure ottieni immediatamente SQLITE_BUSY. Quando qualcuno tiene un blocco nel database, altri tentativi di blocco comporteranno SQLITE_BUSY.

Affrontare SQLITE_BUSY è qualcosa che devi decidere per te. Per molte applicazioni, in attesa di un secondo o due e poi riprovare funziona abbastanza bene, rinunciando dopo i tentativi falliti n. Ci sono gli helper API sqlite3 che rendono questo facile, ad es. sqlite3_busy_handler() e sqlite3_busy_timeout() ma può essere eseguito anche manualmente.

È anche possibile utilizzare la sincronizzazione a livello di sistema operativo per acquisire un blocco mutex nel database oppure utilizzare la messaggistica inter-thread/inter-processo a livello di sistema operativo per segnalare quando un thread ha terminato l'accesso al database.

+0

So che uno deve utilizzare le transazioni in un unico processo. Tuttavia, la mia situazione è che ho più processi, al contrario di più thread, che accedono allo stesso DB contemporaneamente. Le transazioni SQLite gestiscono realmente tale concorrenza!?!? –

+0

@Tom: Sì, nel livello di porting specifico per il sistema operativo sqlite3 esiste una funzionalità per il blocco che funziona attraverso i processi. Vedere http://www.sqlite.org/lockingv3.html per ulteriori informazioni – laalto

+1

DEFERRED significa effettivamente che il database non è (condiviso) bloccato finché non vi si accede da una lettura o da una scrittura dopo l'istruzione BEGIN (sì, dovrebbe bloccarsi leggere). IMMEDIATE significa che il database è bloccato immediatamente dopo l'esecuzione di "INIZIA IMMEDIATA TRANSAZIONE". Vedi http://www.sqlite.org/lang_transaction.html –

2

Qualsiasi primitiva SQLite restituirà SQLITE_BUSY se tenta di accedere a un altro database che accede contemporaneamente. È possibile verificare il codice di errore e ripetere l'azione.

In alternativa è possibile utilizzare la sincronizzazione del sistema operativo - mutex su MS Windows o qualcosa di simile su altri sistemi operativi. Il processo proverà ad acquisire il mutex e se qualcuno lo detiene già, il processo verrà bloccato fino a quando l'altro processo non avrà completato l'operazione e rilascerà il mutex. Bisogna fare attenzione per evitare casi in cui il processo acquisisce il mutext e quindi non lo rilascia mai.

+1

Hmm, SQLite non fornisce i blocchi per proteggere l'accesso ai file del database ?? –

0

Lo SQLite FAQ circa esattamente this

+1

Ho letto le FAQ prima di pubblicare la mia domanda qui. Ovviamente avrei dovuto dirlo (questa era la lezione numero due che ho imparato oggi). Non riuscivo a vedere esattamente cosa volessero dire. Devo gestire tutte le operazioni di blocco da solo o SQLite supporta questo? "Quando qualsiasi processo vuole scrivere, deve bloccare l'intero file del database per la durata del suo aggiornamento, ma normalmente ci vogliono solo pochi millisecondi, altri processi aspettano solo che lo scrittore finisca e poi proseguono sulla loro attività". Ci vorrebbe qualche sforzo per implementare questo per me stesso. –

+0

Non solo è noioso, è anche soggetto a errori. E spero che SQLite abbia il supporto necessario, nel qual caso mi chiedo quali funzioni dovrei usare. Come nota a margine, penso che la documentazione di SQLite sia un po 'troppo contenuta quando si tratta di esempi con codice sorgente ... –

+0

https://meta.stackexchange.com/questions/225370/your-answer-is-in-another- castello-quando-è-una-risposta-non-an-risposta –

2

Fondamentalmente è necessario avvolgere il vostro codice di accesso ai dati con le transazioni. Ciò manterrà i tuoi dati coerenti. Nient'altro è richiesto.

In SQLite si utilizza

iniziare la transazione

COMMIT TRANSACTION

coppie per delimitare le transazioni. Metti il ​​tuo codice SQL in mezzo per farlo eseguire in una singola transazione.

Tuttavia, come le persone precedenti hanno commentato prima di me, è necessario prestare molta attenzione ai problemi di concorrenza. SQLite può funzionare abbastanza velocemente se utilizzato per l'accesso in lettura (più lettori non sono bloccati e possono essere eseguiti contemporaneamente).

Tuttavia, l'immagine cambia considerevolmente se il codice intercala l'accesso in scrittura e in lettura. Con SQLite, l'intero file del database verrà bloccato anche se è attivo un singolo writer.

Problemi correlati