Transazioni e controllo della concorrenza ottimistica
SI APPLICA A: NoSQL
Le transazioni di database offrono un modello di programmazione sicuro e prevedibile per gestire le modifiche simultanee ai dati. I database relazionali tradizionali come SQL Server consentono di scrivere la logica di business usando stored procedure e/o trigger e inviarla al server per l'esecuzione direttamente nel motore di database. Con i tradizionali database relazionali, è necessario ricorrere a due diversi linguaggi di programmazione: il linguaggio di programmazione dell'applicazione (non transazionale), ad esempio JavaScript, Python, C#, Java e così via, e il linguaggio di programmazione transazionale (T-SQL), che viene eseguito in modo nativo dal database.
Il motore di database in Azure Cosmos DB supporta transazioni conformi ACID con l'isolamento dello snapshot. Tutte le operazioni di database all'interno dell'ambito di una partizione logica del contenitore vengono eseguite a livello di transazione all'interno del motore di database ospitato dalla replica della partizione. Tali operazioni includono sia operazioni di scrittura (aggiornamento di uno o più elementi all'interno della partizione logica) e lettura. Nella tabella seguente vengono illustrate diverse operazioni e tipi di transazione:
Operazione | Tipo di operazione | Transazione singola o con più elementi |
---|---|---|
Inserimento (senza un trigger di pre/post) | Scrittura | Transazione di un singolo elemento |
Inserimento (con un trigger di pre/post) | Lettura e scrittura | Transazione di più elementi |
Sostituzione (senza un trigger di pre/post) | Scrittura | Transazione di un singolo elemento |
Sostituzione (con un trigger di pre/post) | Lettura e scrittura | Transazione di più elementi |
Upsert (senza un trigger di pre/post) | Scrittura | Transazione di un singolo elemento |
Upsert (con un trigger di pre/post) | Lettura e scrittura | Transazione di più elementi |
Eliminazione (senza un trigger di pre/post) | Scrittura | Transazione di un singolo elemento |
Eliminazione (con un trigger di pre/post) | Lettura e scrittura | Transazione di più elementi |
Esegui stored procedure | Lettura e scrittura | Transazione di più elementi |
Il sistema ha avviato l'esecuzione di una procedure di unione | Scrittura | Transazione di più elementi |
Il sistema ha avviato l'esecuzione dell'eliminazione di elementi in base alla scadenza (durata TTL) di un elemento | Scrittura | Transazione di più elementi |
Lettura | Lettura | Transazione di un singolo elemento |
Feed di modifiche | Lettura | Transazione di più elementi |
Lettura impaginata | Lettura | Transazione di più elementi |
Query impaginata | Lettura | Transazione di più elementi |
Eseguire la funzione definita dall'utente come parte della query impaginata | Lettura | Transazione di più elementi |
Transazioni di più elementi
Azure Cosmos DB consente di scrivere stored procedure, trigger pre/post, funzioni definite dall'utente (UDF) e procedure di unione in JavaScript. Azure Cosmos DB supporta in modo nativo l'esecuzione di JavaScript nel relativo motore di database. È possibile registrare stored procedure, trigger pre/post, funzioni definite dall'utente (UDF) e procedure di merge in un contenitore e successivamente eseguirli a livello transazionale all'interno del motore di database di Azure Cosmos DB. La scrittura della logica di applicazione in JavaScript permette l'espressione naturale del flusso di controllo, definizione dell'ambito delle variabili e assegnazione e integrazione delle primitive di gestione delle eccezioni con transazioni di database direttamente sotto forma di linguaggio di programmazione JavaScript.
Sulle stored procedure, trigger, UDF e procedure di unione basati su JavaScript viene eseguito il wrapping all'interno di una transazione di ambiente ACID con isolamento dello snapshot tra tutti gli elementi all'interno della partizione logica. Se JavaScript genera un'eccezione durante l'esecuzione, l'intera transazione sarà interrotta e verrà eseguito il rollback. Il modello di programmazione risultante è semplice ma efficace. Gli sviluppatori JavaScript ottengono un modello di programmazione durevole, usando al tempo stesso i costrutti dei propri linguaggi preferiti e i primitivi di librerie.
La possibilità di eseguire JavaScript direttamente nel motore di database offre prestazioni ed esecuzione transazionale di operazioni di database negli elementi di un contenitore. Poiché il motore di database di Azure Cosmos DB supporta in modo nativo JSON e JavaScript, non vi sono eventuali mancate corrispondenze di impedenza tra i sistemi di tipi di un applicazione e del database.
Controllo della concorrenza ottimistica
Il controllo della concorrenza ottimistica consente di evitare la perdita di aggiornamenti ed eliminazioni. Operazioni simultanee in conflitto vengono sottoposte al regolare blocco pessimistico del motore di database ospitato dalla partizione logica che possiede l'elemento. Quando due operazioni simultanee tentano di aggiornare la versione più recente di un elemento all'interno di una partizione logica, una di esse avrà la precedenza e l'altra avrà esito negativo. Tuttavia, se una o due operazioni che tentano di aggiornare contemporaneamente lo stesso elemento avevano precedentemente letto un valore meno recente dell'elemento, il database non riconosce se il valore precedentemente letto da una o entrambe le operazioni in conflitto era effettivamente il valore più recente dell'elemento. Fortunatamente, questa situazione può essere rilevata con il controllo di concorrenza ottimistica prima che le due operazioni entrino nel limite della transazione all'interno del motore di database. Il controllo di concorrenza ottimistica protegge i dati impedendo che vengano sovrascritte le modifiche apportate da altri utenti. Impedisce anche ad altri utenti di sovrascrivere accidentalmente le proprie modifiche.
Implementazione del controllo di concorrenza ottimistica tramite intestazioni ETag e HTTP
Ogni elemento archiviato in un contenitore di Azure Cosmos ha una proprietà _etag
definita dal sistema. Il valore di _etag
viene automaticamente generato e aggiornato dal server ogni volta che viene aggiornato l'elemento. La proprietà _etag
può essere usata con l'intestazione della richiesta if-match
fornita dal client per consentire al server di stabilire se un elemento può essere aggiornato in modo condizionale. Se il valore dell'intestazione if-match
corrisponde al valore della proprietà _etag
nel server, l'elemento viene aggiornato di conseguenza. Se il valore dell'intestazione della richiesta if-match
non è aggiornato, il server rifiuta l'operazione con un messaggio di risposta di tipo "HTTP 412 - Errore di precondizione". Il client può quindi recuperare nuovamente l'elemento per acquisire la versione corrente nel server o eseguire l'override della versione dell'elemento nel server con il proprio valore _etag
per l'elemento. Inoltre, la proprietà _etag
può essere usata con l'intestazione if-none-match
per stabilire se è necessario ripetere il recupero di una risorsa.
Il valore _etag
dell'elemento cambia ogni volta che l'elemento viene aggiornato. Per le operazioni di sostituzione degli elementi, è necessario esprimere if-match
in modo esplicito come parte delle opzioni della richiesta. Per un esempio, vedere il codice di esempio in GitHub. I valori _etag
sono controllati in modo implicito per tutti gli elementi scritti interessati da una stored procedure. Se viene rilevato un conflitto, la stored procedure eseguirà il rollback della transazione e genererà un'eccezione. Con questo metodo, tutte o nessuna scrittura all'interno della stored procedure viene applicata in modo atomico. Si tratta di un segnale per l'applicazione per riapplicare gli aggiornamenti e ripetere la richiesta del client originale.
Controllo di concorrenza ottimistica e distribuzione globale
Gli aggiornamenti simultanei di un oggetto sono soggetti al controllo di concorrenza ottimistica dal livello di protocollo di comunicazione di Azure Cosmos DB. Per gli account Azure Cosmos DB configurati per scritture in una singola area, Azure Cosmos DB garantisce che la versione lato client dell'elemento che si sta aggiornando (o eliminando) corrisponda alla versione dell'elemento nel contenitore Azure Cosmos DB. Questo garantisce che le scritture non vengano sovrascritte accidentalmente dalle operazioni di scrittura di altri utenti e viceversa. In un ambiente multiutente, il controllo della concorrenza ottimistica protegge l'utente da un'accidentale eliminazione o aggiornamento della versione errata di un elemento. Di conseguenza, gli elementi sono protetti contro i famigerati problemi di "aggiornamento perso" o "eliminazione persa".
In un account Azure Cosmos DB configurato con scritture in più aree, è possibile eseguire il commit dei dati in modo indipendente nelle aree secondarie se il relativo _etag
corrisponde a quello dei dati nell'area locale. Una volta eseguito il commit dei nuovi dati in locale in un'area secondaria, viene quindi uniti nell'hub o nell'area primaria. Se i criteri di risoluzione dei conflitti uniscono i nuovi dati nell'area dell'hub, questi dati verranno replicati a livello globale con il nuovo _etag
. Se i criteri di risoluzione dei conflitti rifiutano i nuovi dati, verrà eseguito il rollback dell'area secondaria ai dati e all'_etag
originali.
Passaggi successivi
Altre informazioni sulle transazioni del database e il controllo della concorrenza ottimistica negli articoli seguenti: