Java 8 ha raggiunto la fine del supporto
e verrà
ritirato
il 31 gennaio 2026. Dopo il ritiro, non potrai eseguire il deployment di applicazioni Java 8, anche se la tua organizzazione ha utilizzato in precedenza un criterio dell'organizzazione per riattivare i deployment di runtime legacy. Le tue applicazioni Java 8 esistenti continueranno a essere eseguite e a ricevere traffico dopo la
data di ritiro. Ti consigliamo di
eseguire la migrazione all'ultima versione supportata di Java.
Strutturazione dei dati per una coerenza elevata
Mantieni tutto organizzato con le raccolte
Salva e classifica i contenuti in base alle tue preferenze.
Datastore offre alta disponibilità, scalabilità e durabilità distribuendo i dati su più macchine e utilizzando la replica sincrona su un'ampia area geografica. Tuttavia, questo design presenta un compromesso: la velocità effettiva di scrittura per qualsiasi singolo gruppo di entità è limitata a circa un commit al secondo e ci sono limitazioni per le query o le transazioni che interessano più gruppi di entità. Questa pagina descrive queste limitazioni in modo più dettagliato e illustra le best practice per strutturare i dati in modo da supportare una coerenza elevata, soddisfacendo al contempo i requisiti di velocità effettiva di scrittura dell'applicazione.
Le letture a elevata coerenza restituiscono sempre i dati correnti e, se eseguite all'interno di una transazione, sembreranno provenire da un'unica istantanea coerente. Tuttavia,
le query devono specificare un filtro di antenati per essere fortemente coerenti o
partecipare a una transazione e le transazioni possono coinvolgere al massimo 25 gruppi di entità. Le letture con coerenza finale non presentano queste limitazioni e sono
adeguate in molti casi. L'utilizzo di letture coerenti alla fine può consentire di
distribuire i dati tra un numero maggiore di gruppi di entità, consentendoti di
ottenere un maggiore throughput di scrittura eseguendo commit in parallelo sui
diversi gruppi di entità. Tuttavia, devi comprendere le caratteristiche delle letture
alla fine coerenti per determinare se sono adatte alla tua applicazione:
- I risultati di queste letture potrebbero non riflettere le transazioni più recenti. Ciò
può verificarsi perché queste letture non garantiscono che la replica su cui vengono eseguite
sia aggiornata. Utilizzano invece i dati disponibili nella replica
al momento dell'esecuzione della query. La latenza di replica è quasi sempre inferiore
a pochi secondi.
- Una transazione confermata che ha interessato più entità potrebbe sembrare
essere stata applicata ad alcune entità e non ad altre. Tieni presente, tuttavia, che una transazione non verrà mai visualizzata come applicata parzialmente all'interno di una singola entità.
- I risultati della query possono includere entità che non avrebbero dovuto essere incluse
in base ai criteri di filtro e potrebbero escludere entità che avrebbero dovuto
essere incluse. Ciò può verificarsi perché gli indici potrebbero essere letti a una versione diversa da quella dell'entità stessa.
Per capire come strutturare i dati per una elevata coerenza, confronta due
approcci diversi per una semplice applicazione guestbook. Il primo approccio
crea una nuovaentità basee per ogni entità creata:
Esegue quindi una query sul tipo di entità Greeting
per i dieci saluti più recenti.
Tuttavia, poiché utilizzi una query non discendente, la replica utilizzata per eseguire
la query in questo schema potrebbe non aver visto il nuovo saluto al momento dell'esecuzione
della query. Tuttavia, quasi tutte le scritture saranno disponibili per
query non discendenti entro pochi secondi dal commit. Per molte applicazioni, una soluzione che fornisce i risultati di una query non discendente nel contesto delle modifiche dell'utente corrente sarà in genere sufficiente a rendere completamente accettabili queste latenze di replica.
Se la elevata coerenza è importante per la tua applicazione, un approccio alternativo è
scrivere entità con un percorso antenato che identifichi la stessa entità base
in tutte le entità che devono essere lette in una singola query antenato
fortemente coerente:
Potrai quindi eseguire una query da predecessore fortemente coerente all'interno del
gruppo di entità identificato dall'entità basee comune:
Questo approccio garantisce una elevata coerenza scrivendo a un singolo gruppo di entità
per guestbook, ma limita anche le modifiche al guestbook a non più di
una scrittura al secondo (il limite supportato per i gruppi di entità). Se è probabile che la tua applicazione
incontri un utilizzo di scrittura più intenso, potresti dover prendere in considerazione l'utilizzo
di altri mezzi: ad esempio, potresti inserire i post recenti in una
memcache con una scadenza
e visualizzare un mix di post recenti dalla memcache e
Datastore oppure potresti memorizzarli nella cache in un cookie, inserire uno stato
nell'URL o altro ancora. L'obiettivo è trovare una soluzione di memorizzazione nella cache
che fornisca i dati per l'utente corrente per il periodo di tempo in cui
l'utente pubblica contenuti nella tua applicazione. Ricorda che se esegui un'operazione get, una query
ancestor o qualsiasi operazione all'interno di una transazione, vedrai sempre i dati scritti più
di recente.
Salvo quando diversamente specificato, i contenuti di questa pagina sono concessi in base alla licenza Creative Commons Attribution 4.0, mentre gli esempi di codice sono concessi in base alla licenza Apache 2.0. Per ulteriori dettagli, consulta le norme del sito di Google Developers. Java è un marchio registrato di Oracle e/o delle sue consociate.
Ultimo aggiornamento 2025-09-04 UTC.
[[["Facile da capire","easyToUnderstand","thumb-up"],["Il problema è stato risolto","solvedMyProblem","thumb-up"],["Altra","otherUp","thumb-up"]],[["Difficile da capire","hardToUnderstand","thumb-down"],["Informazioni o codice di esempio errati","incorrectInformationOrSampleCode","thumb-down"],["Mancano le informazioni o gli esempi di cui ho bisogno","missingTheInformationSamplesINeed","thumb-down"],["Problema di traduzione","translationIssue","thumb-down"],["Altra","otherDown","thumb-down"]],["Ultimo aggiornamento 2025-09-04 UTC."],[[["\u003cp\u003eThis API is compatible with first-generation runtimes and can be used when upgrading to the corresponding second-generation runtimes, with a separate migration guide available for those updating to App Engine Java 11/17.\u003c/p\u003e\n"],["\u003cp\u003eDatastore ensures high availability, scalability, and durability through data distribution and synchronous replication, but write throughput is limited to one commit per second for a single entity group, with restrictions on queries or transactions spanning multiple groups.\u003c/p\u003e\n"],["\u003cp\u003eStrongly-consistent reads provide current data and a consistent snapshot within transactions, requiring an ancestor filter for queries and limiting transactions to 25 entity groups, while eventually-consistent reads offer more flexibility but may not reflect the latest transactions.\u003c/p\u003e\n"],["\u003cp\u003eFor applications needing strong consistency, structuring data with a common ancestor path enables strongly-consistent ancestor queries, although this limits writes to one per second per entity group.\u003c/p\u003e\n"],["\u003cp\u003eFor applications with high write usage, consider using alternative solutions such as memcache or cookies to cache recent posts and display a mix of recent data alongside Datastore results.\u003c/p\u003e\n"]]],[],null,["# Structuring Data for Strong Consistency\n\n| This API is supported for first-generation runtimes and can be used when [upgrading to corresponding second-generation runtimes](/appengine/docs/standard/\n| java-gen2\n|\n| /services/access). If you are updating to the App Engine Java 11/17 runtime, refer to the [migration guide](/appengine/migration-center/standard/migrate-to-second-gen/java-differences) to learn about your migration options for legacy bundled services.\n\nDatastore provides high availability, scalability and durability by\ndistributing data over many machines and using synchronous\nreplication over a wide geographic area. However, there is a tradeoff in this\ndesign, which is that the write throughput for any single\n[*entity group*](/appengine/docs/legacy/standard/java/datastore/entities#Ancestor_paths) is limited to about\none commit per second, and there are limitations on queries or transactions that\nspan multiple entity groups. This page describes these limitations in more\ndetail and discusses best practices for structuring your data to support strong\nconsistency while still meeting your application's write throughput\nrequirements.\n\nStrongly-consistent reads always return current data, and, if performed within a\ntransaction, will appear to come from a single, consistent snapshot. However,\nqueries must specify an ancestor filter in order to be strongly-consistent or\nparticipate in a transaction, and transactions can involve at most 25 entity\ngroups. Eventually-consistent reads do not have those limitations, and are\nadequate in many cases. Using eventually-consistent reads can allow you to\ndistribute your data among a larger number of entity groups, enabling you to\nobtain greater write throughput by executing commits in parallel on the\ndifferent entity groups. But, you need to understand the characteristics of\neventually-consistent reads in order to determine whether they are suitable for\nyour application:\n\n- The results from these reads might not reflect the latest transactions. This can occur because these reads do not ensure that the replica they are running on is up-to-date. Instead, they use whatever data is available on that replica at the time of query execution. Replication latency is almost always less than a few seconds.\n- A committed transaction that spanned multiple entities might appear to have been applied to some of the entities and not others. Note, though, that a transaction will never appear to have been partially applied within a single entity.\n- The query results can include entities that should not have been included according to the filter criteria, and might exclude entities that should have been included. This can occur because indexes might be read at a different version than the entity itself is read at.\n\nTo understand how to structure your data for strong consistency, compare two\ndifferent approaches for a simple guestbook application. The first approach\ncreates a new root entity for each entity that is created: \n\n protected Entity createGreeting(\n DatastoreService datastore, User user, Date date, String content) {\n // No parent key specified, so Greeting is a root entity.\n Entity greeting = new Entity(\"Greeting\");\n greeting.setProperty(\"user\", user);\n greeting.setProperty(\"date\", date);\n greeting.setProperty(\"content\", content);\n\n datastore.put(greeting);\n return greeting;\n }\n\nIt then queries on the entity kind `Greeting` for the ten most recent greetings. \n\n protected List\u003cEntity\u003e listGreetingEntities(DatastoreService datastore) {\n Query query = new Query(\"Greeting\").addSort(\"date\", Query.SortDirection.DESCENDING);\n return datastore.prepare(query).asList(FetchOptions.Builder.withLimit(10));\n }\n\nHowever, because you are using a non-ancestor query, the replica used to perform\nthe query in this scheme might not have seen the new greeting by the time the\nquery is executed. Nonetheless, nearly all writes will be available for\nnon-ancestor queries within a few seconds of commit. For many applications, a\nsolution that provides the results of a non-ancestor query in the context of the\ncurrent user's own changes will usually be sufficient to make such replication\nlatencies completely acceptable.\n\nIf strong consistency is important to your application, an alternate approach is\nto write entities with an ancestor path that identifies the same root entity\nacross all entities that must be read in a single, strongly-consistent ancestor\nquery: \n\n protected Entity createGreeting(\n DatastoreService datastore, User user, Date date, String content) {\n // String guestbookName = \"my guestbook\"; -- Set elsewhere (injected to the constructor).\n Key guestbookKey = KeyFactory.createKey(\"Guestbook\", guestbookName);\n\n // Place greeting in the same entity group as guestbook.\n Entity greeting = new Entity(\"Greeting\", guestbookKey);\n greeting.setProperty(\"user\", user);\n greeting.setProperty(\"date\", date);\n greeting.setProperty(\"content\", content);\n\n datastore.put(greeting);\n return greeting;\n }\n\nYou will then be able to perform a strongly-consistent ancestor query within the\nentity group identified by the common root entity: \n\n protected List\u003cEntity\u003e listGreetingEntities(DatastoreService datastore) {\n Key guestbookKey = KeyFactory.createKey(\"Guestbook\", guestbookName);\n Query query =\n new Query(\"Greeting\", guestbookKey)\n .setAncestor(guestbookKey)\n .addSort(\"date\", Query.SortDirection.DESCENDING);\n return datastore.prepare(query).asList(FetchOptions.Builder.withLimit(10));\n }\n\nThis approach achieves strong consistency by writing to a single entity group\nper guestbook, but it also limits changes to the guestbook to no more than\n1 write per second (the supported limit for entity groups). If your application\nis likely to encounter heavier write usage, you might need to consider using\nother means: for example, you might put recent posts in a\n[memcache](/appengine/docs/legacy/standard/java/memcache) with an expiration\nand display a mix of recent posts from the memcache and\nDatastore, or you might cache them in a cookie, put some state\nin the URL, or something else entirely. The goal is to find a caching solution\nthat provides the data for the current user for the period of time in which the\nuser is posting to your application. Remember, if you do a get, an ancestor\nquery, or any operation within a transaction, you will always see the most\nrecently written data."]]