Objek Data Java (JDO) adalah antarmuka standar untuk mengakses database di Java, yang menyediakan pemetaan antara class Java dan tabel database. Ada plugin open source yang tersedia untuk menggunakan JDO dengan Datastore, dan halaman ini memberikan informasi tentang cara memulainya.
Peringatan: Menurut kami, sebagian besar developer akan memiliki pengalaman yang lebih baik menggunakan Datastore API tingkat rendah, atau salah satu API open source yang dikembangkan khusus untuk Datastore, seperti Objectify. JDO dirancang untuk digunakan dengan database relasional tradisional, sehingga tidak memiliki cara untuk secara eksplisit mewakili beberapa aspek Datastore yang membuatnya berbeda dengan database relasional, seperti entity group dan kueri ancestor. Hal ini dapat menyebabkan masalah ringan yang sulit dipahami dan diperbaiki.
App Engine Java SDK menyertakan plugin DataNucleus versi 2.x untuk App Engine. Plugin ini sesuai dengan DataNucleus Access Platform versi 3.0, yang memungkinkan Anda menggunakan App Engine Datastore melalui JDO 3.0.
Lihat dokumentasi Access Platform 3.0 untuk informasi selengkapnya tentang JDO. Secara khusus, lihat JDO Mapping dan JDO API.
Peringatan: Plugin DataNucleus 2.x untuk App Engine menggunakan DataNucleus v3.x. Plugin baru ini tidak sepenuhnya kompatibel dengan versi lama dengan plugin (1.x) sebelumnya. Jika Anda mengupgrade ke versi baru, pastikan untuk mengupdate dan menguji aplikasi.
Alat build yang mendukung JDO 2.x dan 3.0
Anda dapat menggunakan Maven untuk menggunakan plugin DataNucleus versi 2.x atau 3.0 untuk App Engine:
- Untuk pengguna Maven: Anda dapat meningkatkan class dengan konfigurasi
berikut di 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>
Bermigrasi ke Versi 2.x Plugin DataNucleus
Bagian ini memberikan petunjuk untuk mengupgrade aplikasi Anda agar dapat menggunakan plugin DataNucleus versi 2.x untuk App Engine, yang sesuai dengan DataNucleus Access Platform 3.0 dan JDO 3.0. Plugin ini tidak sepenuhnya kompatibel dengan versi lama dengan plugin 1.x dan dapat berubah. Jika Anda mengupgrade, pastikan untuk mengupdate dan menguji kode aplikasi.
Perilaku Default Baru
Plugin App Engine DataNucleus versi 2.x memiliki beberapa default yang berbeda dari versi sebelumnya:
- Panggilan non-transaksi ke
PersistenceManager.makePersistent()
, danPersistenceManager.deletePersistent()
sekarang dijalankan secara atomik. (Fungsi ini sebelumnya dijalankan pada transaksi berikutnya atau padaPersistenceManager.close()
.) - Sekarang tidak ada lagi pengecualian pada alokasi PersistenceManagerFactory (PMF) duplikat. Namun, jika Anda memiliki properti persistensi
datanucleus.singletonPMFForName
yang ditetapkan ke true, properti tersebut akan menampilkan PMF singleton yang saat ini dialokasikan untuk nama tersebut. - Hubungan yang tidak dimiliki kini didukung. Lihat Hubungan yang Tidak Dimiliki.
Perubahan pada File Konfigurasi
Untuk mengupgrade aplikasi ke plugin App Engine DataNucleus versi 2.x, Anda perlu mengubah setelan konfigurasi di build.xml
dan jdoconfig.xml
.
Peringatan! Setelah mengupdate konfigurasi, Anda harus menguji kode aplikasi untuk memastikan kompatibilitas mundur. Jika Anda menyiapkan aplikasi baru dan ingin menggunakan plugin versi terbaru, lanjutkan ke Menyiapkan JDO 3.0.
- Properti
PersistenceManagerFactoryClass
telah berubah. Ubah baris ini dijdoconfig.xml
:
<property name="javax.jdo.PersistenceManagerFactoryClass" value="org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/>
menjadi:
<property name="javax.jdo.PersistenceManagerFactoryClass" value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/>
Di build.xml
Target copyjars
perlu berubah untuk mengakomodasi
DataNucleus 2.x:
- Target
copyjars
telah diubah. Perbarui bagian ini:
menjadi:<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>
- Target
datanucleusenhance
telah diubah. Perbarui bagian ini:
menjadi:<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>
Menyiapkan JDO 3.0
Untuk menggunakan JDO guna mengakses datastore, aplikasi App Engine memerlukan hal berikut:
- JAR untuk JDO dan plugin DataNucleus harus berada di direktori
war/WEB-INF/lib/
aplikasi. - File konfigurasi bernama
jdoconfig.xml
harus ada di direktoriwar/WEB-INF/classes/META-INF/
aplikasi, dengan konfigurasi yang memberi tahu JDO untuk menggunakan datastore App Engine. - Proses build project harus melakukan langkah "peningkatan" pascakompilasi pada class data yang dikompilasi untuk mengaitkannya dengan implementasi JDO.
Menyalin JAR
JDO dan JAR datastore disertakan dengan App Engine Java SDK. Anda dapat
menemukannya di direktori
appengine-java-sdk/lib/opt/user/datanucleus/v2/
.
Salin JAR ke direktori war/WEB-INF/lib/
aplikasi Anda.
Pastikan appengine-api.jar
juga ada dalam
direktori war/WEB-INF/lib/
. (Anda mungkin sudah menyalin ini saat
membuat project.) Plugin App Engine DataNucleus menggunakan JAR ini untuk
mengakses datastore.
Membuat File jdoconfig.xml
Antarmuka JDO memerlukan file konfigurasi bernama jdoconfig.xml
di direktori war/WEB-INF/classes/META-INF/
aplikasi. Anda
dapat membuat file ini di lokasi ini secara langsung, atau meminta proses build menyalin
file ini dari direktori sumber.
Buat file dengan konten berikut:
<?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>
Menetapkan Kebijakan Baca Datastore dan Batas Waktu Panggilan
Seperti yang dijelaskan di halaman Kueri Datastore, Anda dapat menyesuaikan perilaku Datastore dengan menetapkan kebijakan baca (konsistensi kuat versus konsistensi tertunda) dan batas waktu panggilan. Di JDO, Anda
melakukannya dengan menentukan nilai yang diinginkan dalam
elemen <persistence-manager-factory>
dari
file jdoconfig.xml
. Semua panggilan yang dilakukan dengan instance
PersistenceManager
tertentu akan menggunakan nilai konfigurasi yang akan
berlaku saat pengelola dibuat oleh
PersistenceManagerFactory
. Anda juga dapat mengganti setelan ini untuk
satu objek Query
.
Untuk menetapkan kebijakan baca untuk PersistenceManagerFactory
, sertakan properti bernama datanucleus.appengine.datastoreReadConsistency
.
Nilai yang mungkin adalah EVENTUAL
dan STRONG
: jika tidak
ditentukan, nilai defaultnya adalah STRONG
. (Namun, perlu diperhatikan bahwa setelan ini hanya berlaku untuk kueri ancestor dalam entity group tertentu.
Kueri non-ancestor selalu memiliki konsistensi tertunda, terlepas dari kebijakan baca yang berlaku.)
<property name="datanucleus.appengine.datastoreReadConsistency" value="EVENTUAL" />
Anda dapat menetapkan batas waktu panggilan datastore terpisah untuk operasi baca dan tulis. Untuk operasi baca, gunakan properti standar JDO javax.jdo.option.DatastoreReadTimeoutMillis
. Untuk operasi tulis, gunakan javax.jdo.option.DatastoreWriteTimeoutMillis
. Nilainya adalah
jumlah waktu, dalam milidetik.
<property name="javax.jdo.option.DatastoreReadTimeoutMillis" value="5000" /> <property name="javax.jdo.option.DatastoreWriteTimeoutMillis" value="10000" />
Jika Anda ingin menggunakan transaksi lintas grup (XG), tambahkan properti berikut:
<property name="datanucleus.appengine.datastoreEnableXGTransactions" value="true" />
Anda dapat memiliki beberapa elemen <persistence-manager-factory>
dalam file jdoconfig.xml
yang sama, dengan menggunakan
atribut name
yang berbeda, untuk menggunakan instance PersistenceManager
dengan konfigurasi yang berbeda di aplikasi yang sama. Misalnya, file
jdoconfig.xml
berikut membuat dua kumpulan konfigurasi, satu bernama
"transactions-optional"
dan lainnya bernama
"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>
Lihat Mendapatkan
Instance PersistenceManager di bawah untuk informasi tentang cara membuat
PersistenceManager
dengan set konfigurasi bernama.
Meningkatkan Class Data
JDO menggunakan langkah "peningkatan" pascakompilasi dalam proses build untuk mengaitkan class data dengan implementasi JDO.
Anda dapat melakukan langkah peningkatan pada class yang dikompilasi dari command line dengan perintah berikut:
java -cp classpath com.google.appengine.tools.enhancer.Enhance class-files
classpath harus berisi JAR
appengine-tools-api.jar
dari
direktori appengine-java-sdk/lib/
, serta semua class data
Anda.
Untuk mengetahui informasi selengkapnya tentang DataNucleus bytecode enhancer, lihat dokumentasi DataNucleus.
Mendapatkan Instance PersistenceManager
Aplikasi berinteraksi dengan JDO menggunakan instance class PersistenceManager. Anda mendapatkan instance ini dengan membuat instance dan memanggil metode pada instance class PersistenceManagerFactory. Factory menggunakan konfigurasi JDO untuk membuat instance PersistenceManager.
Karena instance PersistenceManagerFactory memerlukan waktu untuk diinisialisasi, aplikasi harus menggunakan kembali satu instance. Cara mudah untuk mengelola instance PersistenceManagerFactory adalah dengan membuat class wrapper singleton dengan instance statis, seperti berikut:
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; } }
Tips: "transactions-optional"
merujuk pada
nama konfigurasi yang ditetapkan dalam file jdoconfig.xml
. Jika aplikasi
Anda menggunakan beberapa set konfigurasi, Anda harus memperluas kode ini untuk memanggil
JDOHelper.getPersistenceManagerFactory()
seperti yang diinginkan. Kode Anda
harus meng-cache instance singleton setiap
PersistenceManagerFactory
.
Aplikasi menggunakan instance factory untuk membuat satu instance PersistenceManager untuk setiap permintaan yang mengakses datastore.
import javax.jdo.JDOHelper; import javax.jdo.PersistenceManager; import javax.jdo.PersistenceManagerFactory; import PMF; // ... PersistenceManager pm = PMF.get().getPersistenceManager();
Anda menggunakan PersistenceManager untuk menyimpan, mengupdate, dan menghapus objek data, serta menjalankan kueri datastore.
Setelah selesai membuat instance PersistenceManager, Anda harus memanggil metode close()
. Menggunakan instance PersistenceManager
setelah memanggil metode close()
merupakan kesalahan.
try { // ... do stuff with pm ... } finally { pm.close(); }
Fitur JDO 3.0 yang Tidak Didukung
Fitur antarmuka JDO berikut tidak didukung oleh implementasi App Engine:
- Memiliki hubungan many-to-many.
- Kueri "Gabung". Anda tidak dapat menggunakan kolom entity turunan di filter saat menjalankan kueri pada jenis induk. Perhatikan bahwa Anda dapat menguji kolom hubungan induk secara langsung dalam kueri menggunakan kunci.
- Pengelompokan JDOQL dan kueri gabungan lainnya.
- Kueri polimorf. Anda tidak dapat menjalankan kueri class untuk mendapatkan instance subclass. Setiap class diwakili oleh jenis entity terpisah di datastore.
Menonaktifkan Transaksi dan Porting Aplikasi JDO yang Ada
Konfigurasi JDO yang sebaiknya digunakan menetapkan properti bernama datanucleus.appengine.autoCreateDatastoreTxns
ke true
.
Ini adalah properti khusus App Engine yang memberi tahu implementasi JDO untuk mengaitkan transaksi datastore dengan transaksi JDO yang dikelola dalam kode aplikasi. Jika Anda membangun aplikasi baru dari awal, mungkin inilah
yang Anda inginkan. Namun, jika Anda sudah memiliki aplikasi berbasis JDO yang ingin dijalankan di App Engine, sebaiknya gunakan konfigurasi persistensi alternatif yang menetapkan nilai properti ini ke 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>
Untuk memahami alasan kegunaannya, ingat bahwa Anda hanya dapat beroperasi pada objek yang termasuk dalam entity group yang sama dalam sebuah transaksi. Aplikasi yang di-build menggunakan database tradisional biasanya mengasumsikan ketersediaan transaksi global, yang memungkinkan Anda memperbarui kumpulan data apa pun di dalam transaksi. Karena datastore App Engine tidak mendukung transaksi global, App Engine akan menampilkan pengecualian jika kode Anda mengasumsikan ketersediaan transaksi global. Daripada memeriksa codebase (yang berpotensi besar) dan menghapus semua kode pengelolaan transaksi, Anda cukup menonaktifkan transaksi datastore. Ini tidak mengatasi asumsi yang dibuat oleh kode Anda tentang atomicity modifikasi multi-data, tetapi memungkinkan Anda membuat aplikasi berfungsi sehingga Anda dapat berfokus untuk memfaktorkan ulang kode transaksional secara bertahap dan sesuai kebutuhan, bukan sekaligus.