Java Data Objects (JDO) è un'interfaccia standard per accedere ai database in Java, che fornisce una mappatura tra le classi Java e le tabelle del database. È disponibile un plug-in open source per l'utilizzo di JDO con Datastore e questa pagina fornisce informazioni su come iniziare a utilizzarlo.
Avviso: riteniamo che la maggior parte degli sviluppatori avrà un'esperienza migliore utilizzando l'API Datastore di basso livello o una delle API open source sviluppate appositamente per Datastore, come Objectify. JDO è stato progettato per l'utilizzo con i database relazionali tradizionali e, pertanto, non ha modo di rappresentare esplicitamente alcuni aspetti di Datastore che lo rendono diverso dai database relazionali, come i gruppi di entità e le query sugli antenati. Ciò può portare a problemi sottili che sono difficili da comprendere e risolvere.
L'SDK Java di App Engine include la versione 2.x del Plug-in DataNucleus per App Engine. Questo plug-in corrisponde alla versione 3.0 del Piattaforma di accesso DataNucleus, che consente di utilizzare App Engine Datastore tramite JDO 3.0.
Consulta: il Accedi alla documentazione di Platform 3.0 per ulteriori informazioni su JDO. Nella particolare, consulta JDO Mapping e JDO l'API.
Avviso: plug-in DataNucleus 2.x per App Engine utilizza DataNucleus v3.x. Questo nuovo plug-in non è completamente compatibile con le versioni precedenti con il plug-in (1.x) precedente. Se esegui l'upgrade alla nuova versione, assicurati di aggiornare e testare l'applicazione.
Creazione di strumenti che supportano JDO 2.x e 3.0
Puoi usare Maven per usa la versione 2.x o 3.0 del plug-in DataNucleus per App Engine:
- Per gli utenti Maven: puoi migliorare i corsi con quanto segue
configurazioni nel file
pom.xml
:<plugin> <groupId>org.datanucleus</groupId> <artifactId>maven-datanucleus-plugin</artifactId> <version>3.2.0-m1</version> <configuration> <api>JDO</api> <props>${basedir}/datanucleus.properties</props> <verbose>true</verbose> <enhancerName>ASM</enhancerName> </configuration> <executions> <execution> <phase>process-classes</phase> <goals> <goal>enhance</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.datanucleus</groupId> <artifactId>datanucleus-core</artifactId> <version>3.1.3</version> </dependency> </dependencies> </plugin>
Migrazione alla versione 2.x del plug-in DataNucleus
Questa sezione fornisce istruzioni per eseguire l'upgrade dell'app in modo da utilizzare la versione 2.x del plug-in DataNucleus per App Engine, che corrisponde a DataNucleus Access Platform 3.0 e JDO 3.0. Questo plug-in non è completamente compatibile con le versioni precedenti e potrebbe cambiare. Se esegui l'upgrade, assicurati di eseguire l'aggiornamento e del codice della tua applicazione.
Nuovi comportamenti predefiniti
La versione 2.x del plug-in DataNucleus di App Engine ha alcuni valori predefiniti diversi rispetto alla versione precedente:
- Le chiamate non transazionali a
PersistenceManager.makePersistent()
ePersistenceManager.deletePersistent()
vengono ora eseguite in modo atomico. (Queste funzioni sono state eseguite in precedenza nella prossima transazione o in dataPersistenceManager.close()
. - Ora non esiste più un'eccezione per la proprietà PersistenceManagerFA duplicata
(PMF). Se invece hai la proprietà persistenza
datanucleus.singletonPMFForName
impostato su true, allora restituisce il PMF singleton attualmente allocato per quel nome. - Ora sono supportate relazioni senza proprietà. Consulta Relazioni non di proprietà.
Modifiche ai file di configurazione
Per eseguire l'upgrade dell'applicazione alla versione 2.x del plug-in DataNucleus di App Engine, devi modificare le impostazioni di configurazione in build.xml
e jdoconfig.xml
.
Attenzione: Dopo aver aggiornato la configurazione, occorre testare il codice dell'applicazione per verificarne la compatibilità con le versioni precedenti. Se configuri una nuova applicazione e vuoi utilizzare la versione più recente del plug-in, vai a Configurazione di JDO 3.0.
- La proprietà
PersistenceManagerFactoryClass
è cambiata. Cambia questa riga injdoconfig.xml
:
<property name="javax.jdo.PersistenceManagerFactoryClass" value="org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/>
a:
<property name="javax.jdo.PersistenceManagerFactoryClass" value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/>
In build.xml
Il target copyjars
deve essere modificato per soddisfare
DataNucleus 2.x:
- Il target
copyjars
è stato modificato. Aggiorna questa sezione:
a:<target name="copyjars" description="Copies the App Engine JARs to the WAR."> <mkdir dir="war/WEB-INF/lib" /> <copy todir="war/WEB-INF/lib" flatten="true"> <fileset dir="${sdk.dir}/lib/user"> <include name="**/*.jar" /> </fileset> </copy> </target>
<target name="copyjars" description="Copies the App Engine JARs to the WAR."> <mkdir dir="war/WEB-INF/lib" /> <copy todir="war/WEB-INF/lib" flatten="true"> <fileset dir="${sdk.dir}/lib/user"> <include name="**/appengine-api-1.0-sdk*.jar" /> </fileset> <fileset dir="${sdk.dir}/lib/opt/user"> <include name="appengine-api-labs/v1/*.jar" /> <include name="jsr107/v1/*.jar" /> <include name="datanucleus/v2/*.jar" /> </fileset> </copy> </target>
- Il target
datanucleusenhance
è stato modificato. Aggiorna sezione:
a:<target name="datanucleusenhance" depends="compile" description="Performs enhancement on compiled data classes."> <enhance_war war="war" /> </target>
<target name="datanucleusenhance" depends="compile" description="Performs enhancement on compiled data classes."> <enhance_war war="war"> <args> <arg value="-enhancerVersion"/> <arg value="v2"/> </args> </enhance_war> </target>
Configurazione di JDO 3.0
Per utilizzare JDO per accedere al datastore, un'app App Engine ha bisogno di quanto segue:
- I JAR per JDO e il plug-in DataNucleus devono essere nella
Directory
war/WEB-INF/lib/
. - Un file di configurazione denominato
jdoconfig.xml
deve essere nella cartella directorywar/WEB-INF/classes/META-INF/
, con una configurazione indica a JDO di utilizzare il datastore di App Engine. - Il processo di compilazione del progetto deve eseguire un "miglioramento" di post-compilazione passaggio sulle classi di dati compilate per associarle al JDO implementazione.
Copia dei JAR in corso...
I JDO del datastore e i JAR del datastore sono inclusi nell'SDK Java di App Engine. Puoi
trovali in appengine-java-sdk/lib/opt/user/datanucleus/v2/
.
Copia i JAR nel file war/WEB-INF/lib/
dell'applicazione
.
Assicurati che appengine-api.jar
sia anche nel
Directory war/WEB-INF/lib/
. Potresti averlo già copiato al momento della creazione del progetto. Il plug-in DataNucleus di App Engine utilizza questo file JAR per accedere al datastore.
Creazione del file jdoconfig.xml
L'interfaccia JDO richiede un file di configurazione denominato jdoconfig.xml
nella directory war/WEB-INF/classes/META-INF/
dell'applicazione. Tu
puoi creare il file direttamente in questa posizione oppure fare in modo che il processo di compilazione
questo file da una directory di origine.
Crea il file con i seguenti contenuti:
<?xml version="1.0" encoding="utf-8"?> <jdoconfig xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig"> <persistence-manager-factory name="transactions-optional"> <property name="javax.jdo.PersistenceManagerFactoryClass" value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/> <property name="javax.jdo.option.ConnectionURL" value="appengine"/> <property name="javax.jdo.option.NontransactionalRead" value="true"/> <property name="javax.jdo.option.NontransactionalWrite" value="true"/> <property name="javax.jdo.option.RetainValues" value="true"/> <property name="datanucleus.appengine.autoCreateDatastoreTxns" value="true"/> <property name="datanucleus.appengine.singletonPMFForName" value="true"/> </persistence-manager-factory> </jdoconfig>
Impostazione del criterio di lettura del datastore e della scadenza della chiamata
Come descritto sul Datastore
Query, puoi personalizzare il comportamento di Datastore impostando
criterio per la lettura (consistenza elevata rispetto a quella finale) e scadenza della chiamata. In JDO, lo fai specificando i valori desiderati nell'elemento <persistence-manager-factory>
del file jdoconfig.xml
. Tutte le chiamate effettuate con un determinato
L'istanza PersistenceManager
utilizzerà i valori di configurazione in
quando il gestore è stato creato
PersistenceManagerFactory
. Puoi anche eseguire l'override di queste impostazioni
un singolo oggetto Query
.
Per impostare il criterio di lettura per un PersistenceManagerFactory
, includi
una proprietà denominata datanucleus.appengine.datastoreReadConsistency
.
I valori possibili sono EVENTUAL
e STRONG
: se non specificato, il valore predefinito è STRONG
. Tieni presente, tuttavia, che
si applicano solo alle query predecessore all'interno di un determinato gruppo di entità.
Le query non relative all'antenato sono sempre coerenti in modo definitivo, indipendentemente dal
criterio di lettura prevalente.
<property name="datanucleus.appengine.datastoreReadConsistency" value="EVENTUAL" />
Puoi impostare scadenze separate per le chiamate del datastore per letture e scritture. Per le letture, utilizza la proprietà JDO standard javax.jdo.option.DatastoreReadTimeoutMillis
. Per la scrittura, utilizza
javax.jdo.option.DatastoreWriteTimeoutMillis
. Il valore è un
di tempo in millisecondi.
<property name="javax.jdo.option.DatastoreReadTimeoutMillis" value="5000" /> <property name="javax.jdo.option.DatastoreWriteTimeoutMillis" value="10000" />
Se vuoi utilizzare le transazioni tra gruppi (XG), aggiungi la seguente proprietà:
<property name="datanucleus.appengine.datastoreEnableXGTransactions" value="true" />
Puoi avere più <persistence-manager-factory>
elementi nello stesso file jdoconfig.xml
, utilizzando diversi
name
, per utilizzare le istanze PersistenceManager
con configurazioni diverse nella stessa app. Ad esempio,
Il file jdoconfig.xml
stabilisce due insiemi di configurazione, uno denominato
"transactions-optional"
e un altro nome
"eventual-reads-short-deadlines"
:
<?xml version="1.0" encoding="utf-8"?> <jdoconfig xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig"> <persistence-manager-factory name="transactions-optional"> <property name="javax.jdo.PersistenceManagerFactoryClass" value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/> <property name="javax.jdo.option.ConnectionURL" value="appengine"/> <property name="javax.jdo.option.NontransactionalRead" value="true"/> <property name="javax.jdo.option.NontransactionalWrite" value="true"/> <property name="javax.jdo.option.RetainValues" value="true"/> <property name="datanucleus.appengine.autoCreateDatastoreTxns" value="true"/> </persistence-manager-factory> <persistence-manager-factory name="eventual-reads-short-deadlines"> <property name="javax.jdo.PersistenceManagerFactoryClass" value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/> <property name="javax.jdo.option.ConnectionURL" value="appengine"/> <property name="javax.jdo.option.NontransactionalRead" value="true"/> <property name="javax.jdo.option.NontransactionalWrite" value="true"/> <property name="javax.jdo.option.RetainValues" value="true"/> <property name="datanucleus.appengine.autoCreateDatastoreTxns" value="true"/> <property name="datanucleus.appengine.datastoreReadConsistency" value="EVENTUAL" /> <property name="javax.jdo.option.DatastoreReadTimeoutMillis" value="5000" /> <property name="javax.jdo.option.DatastoreWriteTimeoutMillis" value="10000" /> <property name="datanucleus.singletonPMFForName" value="true" /> </persistence-manager-factory> </jdoconfig>
Consulta la sezione Come ottenere un
PersistenceManager di un'istanza di seguito per informazioni sulla creazione
PersistenceManager
con un set di configurazione denominato.
Miglioramento delle classi di dati
JDO utilizza un "miglioramento" di post-compilazione passaggio nel processo di compilazione associare le classi di dati all'implementazione di JDO.
Puoi eseguire il passaggio di miglioramento sulle classi compilate dalla riga di comando con il seguente comando:
java -cp classpath com.google.appengine.tools.enhancer.Enhance class-files
Il classpath deve contenere il file JARappengine-tools-api.jar
della directoryappengine-java-sdk/lib/
, nonché tutti i tuoi livelli di dati.
Per ulteriori informazioni sul potenziatore bytecode DataNucleus, vedi il documentazione di DataNucleus.
Ottenere un'istanza di PersistenceManager
Un'app interagisce con JDO utilizzando un'istanza della classe PersistenceManager. Puoi ottenere questa istanza creando un'istanza e chiamando un metodo su un'istanza della classe PersistenceManagerFactory. La fabbrica utilizza la configurazione JDO per delle istanze PersistenceManager.
Poiché l'inizializzazione di un'istanza PersistenceManager Fabbrica richiede tempo, deve riutilizzare una singola istanza. Un modo semplice per gestire L'istanza PersistenceManager Fabbrica deve creare una classe wrapper singleton con un statica come segue:
PMF.java
import javax.jdo.JDOHelper; import javax.jdo.PersistenceManagerFactory; public final class PMF { private static final PersistenceManagerFactory pmfInstance = JDOHelper.getPersistenceManagerFactory("transactions-optional"); private PMF() {} public static PersistenceManagerFactory get() { return pmfInstance; } }
Suggerimento: "transactions-optional"
si riferisce alla
nome della configurazione impostata nel file jdoconfig.xml
. Se le tue
utilizza più set di configurazione, devi estendere questo codice per chiamare
JDOHelper.getPersistenceManagerFactory()
a tua scelta. Il tuo codice
memorizza nella cache un'istanza singleton di
PersistenceManagerFactory
.
L'app usa l'istanza di fabbrica per creare un'istanza PersistenceManager per ogni richiesta che accede al datastore.
import javax.jdo.JDOHelper; import javax.jdo.PersistenceManager; import javax.jdo.PersistenceManagerFactory; import PMF; // ... PersistenceManager pm = PMF.get().getPersistenceManager();
Utilizza PersistenceManager per archiviare, aggiornare ed eliminare oggetti dati e per eseguire query sui datastore.
Al termine dell'utilizzo dell'istanza PersistenceManager, devi chiamarne il metodo
close()
. Utilizzare PersistenceManager è un errore
istanza dopo aver chiamato il metodo close()
.
try { // ... do stuff with pm ... } finally { pm.close(); }
Funzionalità non supportate di JDO 3.0
Le seguenti funzionalità dell'interfaccia JDO non sono supportate dall'implementazione di App Engine:
- Relazioni many-to-many di proprietà.
- Query "join". Non puoi utilizzare un campo di un'entità secondaria in un filtro quando esegui una query sul tipo principale. Tieni presente che puoi testare l'impostazione della relazione direttamente nella query utilizzando una chiave.
- Raggruppamento JDOQL e altre query aggregate.
- Query polimorfiche. Non puoi eseguire una query su una classe per ottenere le istanze di una sottoclasse. Ogni classe è rappresentata da un tipo di entità separato nel datastore.
Disabilitazione in corso... Transazioni e portabilità di app JDO esistenti
La configurazione JDO che consigliamo di utilizzare imposta una proprietà denominata
Da datanucleus.appengine.autoCreateDatastoreTxns
a true
.
Si tratta di una proprietà specifica di App Engine che indica all'implementazione JDO di associare le transazioni del datastore alle transazioni JDO gestite nel codice dell'applicazione. Se stai creando una nuova app da zero, probabilmente è ciò che ti serve. Tuttavia, se hai già un'applicazione basata su JDO che vuoi eseguire su App Engine, ti consigliamo di utilizzare una configurazione di persistenza alternativa che imposti il valore di questa proprietà su false
:
<?xml version="1.0" encoding="utf-8"?> <jdoconfig xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig"> <persistence-manager-factory name="transactions-optional"> <property name="javax.jdo.PersistenceManagerFactoryClass" value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/> <property name="javax.jdo.option.ConnectionURL" value="appengine"/> <property name="javax.jdo.option.NontransactionalRead" value="true"/> <property name="javax.jdo.option.NontransactionalWrite" value="true"/> <property name="javax.jdo.option.RetainValues" value="true"/> <property name="datanucleus.appengine.autoCreateDatastoreTxns" value="false"/> </persistence-manager-factory> </jdoconfig>
Per capire perché può essere utile, ricorda che puoi eseguire operazioni solo sugli oggetti che appartengono allo stesso gruppo di entità all'interno di una transazione. Le applicazioni create utilizzando database tradizionali in genere presuppongono la disponibilità di transazioni globali, che consentono di aggiornare qualsiasi set di record transazione. Poiché il datastore di App Engine non supporta le transazioni, App Engine genera eccezioni se il codice assume la disponibilità delle transazioni globali. Invece di analizzare l'URL (potenzialmente grande) codebase e rimuovendo tutto il codice di gestione delle transazioni, puoi semplicemente disabilita le transazioni datastore. Ciò non risolve le supposizioni fatte dal codice sull'atomicità delle modifiche di più record, ma ti consente di far funzionare l'app in modo da poterti concentrare sul refactoring del codice transazionale in modo incrementale e in base alle necessità, anziché tutto in una volta.