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 utilizzando 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 della 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 permette di scrivere stored procedure, trigger pre/post, funzioni definite dall'utente (UDF) e procedure di merge 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 quindi aggiornato. 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: