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 implementasi JDO 2.3 untuk App Engine Datastore. Implementasi ini didasarkan pada DataNucleus Access Platform versi 1.0, yang merupakan implementasi referensi open source untuk JDO 2.3.
Catatan: Petunjuk di halaman ini berlaku untuk JDO versi 2.3, yang menggunakan plugin DataNucleus versi 1.0 untuk App Engine. App Engine kini menawarkan plugin DataNucleus 2.x yang memungkinkan Anda menjalankan JDO 3.0. Plugin baru ini mendukung hubungan yang tidak dimiliki serta menyediakan sejumlah API dan fitur baru. Upgrade ini tidak sepenuhnya kompatibel dengan versi sebelumnya. Jika membangun ulang aplikasi menggunakan JDO 3.0, Anda perlu mengupdate dan mengetes ulang kode. Untuk informasi selengkapnya tentang versi baru, lihat JDO 3.0. Untuk mengetahui informasi selengkapnya tentang cara melakukan upgrade, lihat Menggunakan JDO 3.0 dengan App Engine.
Menyiapkan JDO 2.3
Untuk menggunakan JDO guna mengakses datastore, aplikasi App Engine memerlukan hal berikut:
- JAR plugin JDO dan DataNucleus App Engine harus berada dalam 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 App Engine Datastore. - 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/user/orm/
.
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.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/> <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> </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
. Perlu diperhatikan bahwa setelan ini hanya berlaku untuk kueri ancestor dalam entity group tertentu.
Pada akhirnya, kueri non-ancestor dan lintas grup akan selalu konsisten, terlepas dari kebijakan baca yang berlaku.
<property name="datanucleus.appengine.datastoreReadConsistency" value="EVENTUAL" />
Anda dapat menetapkan batas waktu panggilan datastore yang terpisah untuk pembacaan dan penulisan. 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.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/> <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.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/> <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" /> </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. Untuk menerapkan ini, sebuah pengecualian akan dikeluarkan jika aplikasi membuat lebih dari satu instance PersistenceManagerFactory (dengan nama konfigurasi yang sama) Cara mudah untuk mengelola instance PersistenceManagerFactory adalah dengan membuat class wrapper singleton dengan instance statis, sebagai 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 2.3 yang Tidak Didukung
Fitur antarmuka JDO berikut tidak didukung oleh implementasi App Engine:
- Hubungan yang tidak dimiliki. Anda dapat menerapkan hubungan yang tidak dimiliki menggunakan nilai Kunci eksplisit. Sintaksis JDO untuk hubungan yang tidak dimiliki mungkin didukung dalam rilis mendatang.
- 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.
IdentityType.DATASTORE
untuk anotasi@PersistenceCapable
. Hanya mendukungIdentityType.APPLICATION
.- Saat ini ada bug yang mencegah hubungan one-to-many yang dimiliki apabila induk dan turunan memiliki class yang sama, sehingga sulit untuk membuat model struktur pohon. Hal ini akan diperbaiki dalam rilis mendatang. Anda dapat mengatasi masalah ini dengan menyimpan nilai Kunci eksplisit untuk induk atau turunannya.
Menonaktifkan Transaksi dan Melakukan 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.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/> <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.