Datastore supporta le transazioni. Una transazione è un'operazione o un insieme di operazioni atomiche: o si verificano tutte le operazioni nella transazione o non si verifica nessuna. Un'applicazione può eseguire più operazioni e calcoli in una singola transazione.
Utilizzo delle transazioni
Una transazione è un insieme di operazioni di Datastore su una o più entità. Ogni transazione è garantita come atomica, il che significa che le transazioni non vengono mai applicate parzialmente. Qualsiasi operazione nel transazioni applicate o nessuna di queste viene applicata. Le transazioni hanno un durata massima di 60 secondi con una scadenza di inattività di 10 secondi dopo 30 secondi secondi.
Un'operazione potrebbe non riuscire quando:
- Sono state tentate troppe modifiche simultanee nello stesso gruppo di entità.
- La transazione supera un limite di risorse.
- Datastore rileva un errore interno.
In tutti questi casi, l'API Datastore genera un'eccezione.
Le transazioni sono una funzionalità facoltativa di Datastore; non sei necessarie per utilizzare le transazioni per eseguire operazioni di Datastore.
Ecco un esempio di aggiornamento del campo denominato vacationDays
in un'entità di tipo
Employee
denominata Joe
:
Tieni presente che, per mantenere i nostri esempi più concisi, a volte omettiamo il blocco finally
che esegue un rollback se la transazione è ancora attiva. Nel codice di produzione è importante assicurarsi che ogni transazione sia stata eseguita esplicitamente o sia stato eseguito il rollback.
Gruppi di entità
Ogni entità appartiene a un gruppo di entità, ovvero a un insieme di una o più entità possono essere manipolati in un'unica transazione. Le relazioni tra gruppi di entità in App Engine per archiviare diverse entità nella stessa parte in ogni rete. Una transazione configura le operazioni di Datastore per un gruppo di entità e tutte le operazioni vengono applicate come gruppo o non vengono applicate affatto se la transazione non va a buon fine.
Quando l'applicazione crea un'entità, può assegnare un'altra entità come parent della nuova entità. L'assegnazione di un'entità principale a una nuova entità la inserisce nello stesso gruppo dell'entità principale.
Un'entità senza un'entità padre è un'entità principale. Un'entità padre di anche un'altra entità può avere un elemento padre. Una catena di entità principali da un'entità fino alla radice è il percorso per l'entità e i membri del percorso sono i antenati dell'entità. L'elemento padre di un'entità viene definita quando l'entità creato e non può essere modificato in un secondo momento.
Ogni entità con una determinata entità base come predecessore si trova nella stessa entità gruppo. Tutte le entità di un gruppo vengono archiviate nello stesso nodo Datastore. Una singola transazione può modificare più entità in un unico gruppo o aggiungere nuove entità al gruppo impostando come entità principale una entità esistente nel gruppo. Il seguente snippet di codice illustra le transazioni vari tipi di entità:
Creazione di un'entità in uno specifico gruppo di entità
Quando l'applicazione crea una nuova entità, puoi assegnarla a un gruppo di entità fornendo la chiave di un'altra entità. L'esempio seguente costruisce la
chiave di un'entità MessageBoard
, quindi utilizza la chiave per creare e rendere persistenti
Entità Message
che risiede nello stesso gruppo di entità dell'entità MessageBoard
:
Utilizzo delle transazioni tra gruppi
Le transazioni tra gruppi (chiamate anche transazioni XG) operano su più gruppi gruppi di entità, che si comportano come transazioni a un singolo gruppo descritte sopra, ad eccezione di che le transazioni tra gruppi non vadano a buon fine se il codice tenta di aggiornare entità da più gruppi di entità.
L'utilizzo di una transazione tra gruppi è simile all'utilizzo di una transazione tra gruppi
transazione, ma devi specificare che la transazione venga
eseguire il raggruppamento incrociato quando inizi la transazione, utilizzando
TransactionOptions
:
Operazioni consentite in una transazione
Datastore impone delle restrizioni su ciò che può essere fatto all'interno di una singola transazione.
Tutte le operazioni Datastore in una transazione devono operare nello stesso file gruppo di entità se si tratta di una transazione a un gruppo o su entità in un massimo di venticinque gruppi di entità se la transazione è tra gruppi. Sono incluse le query per le entità in base al predecessore, il recupero delle entità in base alla chiave, l'aggiornamento e l'eliminazione delle entità. Nota che ogni entità base appartiene a un un gruppo di entità separato, quindi una singola transazione non può creare o operare su più di entità base, a meno che non si tratti di una transazione tra gruppi.
Quando due o più transazioni tentano contemporaneamente di modificare entità in uno o più gruppi di entità comuni, solo la prima transazione che esegue il commit delle modifiche può avere esito positivo; tutte le altre non andranno a buon fine al momento del commit. A causa di questo design, l'utilizzo dei gruppi di entità limita il numero di scritture simultanee che puoi eseguire su qualsiasi entità dei gruppi. Quando inizia una transazione, Datastore utilizza il controllo della concorrenza ottimistico controllando l'ora dell'ultimo aggiornamento dei gruppi di entità utilizzati nella transazione. Al momento dell'commit di una transazione per i gruppi di entità, Datastore controlla di nuovo l'ora dell'ultimo aggiornamento dei gruppi di entità utilizzati nella transazione. Se è stato modificato dal controllo iniziale, viene lanciata un'eccezione.
Un'app può eseguire una query durante una transazione, ma solo se include un filtro dei predecessori. Un'app può anche recuperare le entità Datastore per chiave durante una transazione. Puoi preparare le chiavi prima della transazione oppure puoi crearle all'interno della transazione con nomi o ID chiave.
Isolamento e coerenza
Al di fuori delle transazioni, il livello di isolamento di Datastore è più simile alla lettura confermata. All'interno delle transazioni viene applicato l'isolamento serializzabile. Ciò significa che un'altra transazione non può modificare contemporaneamente i dati letti o modificati da questa transazione.
In una transazione, tutte le letture riflettono lo stato attuale e coerente di Datastore al momento dell'inizio della transazione. query e ottiene all'interno di una transazione hanno la garanzia di vedere un unico snapshot coerente Datastore all'inizio della transazione. Le entità e le righe di indice nel gruppo di entità della transazione sono completamente aggiornate in modo che le query restituiscano l'insieme completo e corretto di entità di risultato, senza i falsi positivi o i falsi negativi che possono verificarsi nelle query al di fuori delle transazioni.
Questa vista istantanea coerente si estende anche alle letture dopo le scritture all'interno delle transazioni. A differenza della maggior parte dei database, esegue query e ottiene all'interno di un La transazione Datastore non vede il i risultati delle precedenti scritture all'interno della transazione. Nello specifico, se un'entità viene modificato o eliminato all'interno di una transazione, di una query o di un comando GET versione originale dell'entità all'inizio della transazione o niente se l'entità non esisteva in quel caso.
Utilizzi per le transazioni
Questo esempio mostra un utilizzo delle transazioni: l'aggiornamento di un'entità con un nuovo valore della proprietà rispetto al valore corrente. Poiché l'API Datastore non riprova le transazioni, possiamo aggiungere la logica per la ripetizione della transazione nel caso in cui un'altra richiesta aggiorni contemporaneamente lo stesso MessageBoard
o uno dei suoi Messages
.
È necessaria una transazione perché il valore potrebbe essere aggiornato da un altro utente
dopo che questo codice ha recuperato l'oggetto, ma prima che lo salvi.
Senza una transazione, la richiesta dell'utente utilizza il valore count
prima dell'aggiornamento dell'altro utente e il salvataggio sovrascrive il nuovo valore. Con un
transazione, all'applicazione viene comunicato l'aggiornamento dell'altro utente.
Se l'entità viene aggiornata durante la transazione, la transazione non va a buon fine con un ConcurrentModificationException
. L'applicazione può
ripetere la transazione per utilizzare i nuovi dati.
Un altro uso comune delle transazioni è recuperare un'entità con una chiave denominata, oppure se non esiste ancora:
Come in precedenza, è necessaria una transazione per gestire il caso in cui un altro utente durante il tentativo di creare o aggiornare un'entità con lo stesso ID stringa. Senza una transazione, se l'entità non esiste e due utenti tentano di crearla, il secondo sovrascrive la prima senza sapere che è successo. Con una transazione, il secondo tentativo non va a buon fine a livello atomico. Se ha senso, l'applicazione può riprovare a recuperare l'entità e aggiornarla.
Quando una transazione non va a buon fine, puoi chiedere all'app di riprovare la transazione finché non viene riesce oppure puoi consentire agli utenti di gestire l'errore propagandolo il livello dell'interfaccia utente dell'app. Non è necessario creare un loop di ripetizione ogni transazione.
Infine, puoi utilizzare una transazione per leggere uno snapshot coerente Datastore. Questo può essere utile quando sono necessarie più letture per visualizzare una pagina o esportare dati che devono essere coerenti. Questi tipi di sono chiamate spesso transazioni di sola lettura perché non eseguono scrive. Le transazioni di sola lettura su un singolo gruppo non vanno mai a buon fine a causa di in modo da non dover implementare nuovi tentativi in caso di errore. Tuttavia, le transazioni tra gruppi possono non riuscire a causa di modifiche contemporanee, pertanto dovrebbero avere dei nuovi tentativi. Il commit e il rollback di una transazione di sola lettura entrambi autonomi.
Accodamento delle attività transazionali
Puoi accodare un'attività come parte di una transazione Datastore, ad esempio che l'attività è in coda (e la garanzia sarà accodata) solo se la transazione eseguito correttamente il commit. Se il commit della transazione viene eseguito, l'attività viene saranno accodati. Una volta messa in coda, l'esecuzione dell'attività non è garantita immediatamente e le eventuali operazioni eseguite all'interno dell'attività vengono eseguite indipendentemente dalla transazione originale. L'attività esegue ripetutamente tentativi finché non riesce. Questo vale per qualsiasi attività in coda nel contesto di una transazione.
Le attività transazionali sono utili perché ti consentono azioni non Datastore in un Datastore transazione (ad esempio, l'invio di un'email per confermare un acquisto). Puoi anche associare le azioni di Datastore alla transazione, ad esempio applicare le modifiche a gruppi di entità aggiuntivi al di fuori della transazione se e solo se la transazione va a buon fine.
Un'applicazione non può inserire più di cinque attività transazionali in code di attività durante una una singola transazione. Le attività transazionali non devono avere nomi specificati dall'utente.