Datastore mendukung transaksi. Transaksi adalah operasi atau serangkaian operasi yang bersifat atomik—baik semua operasi dalam transaksi terjadi maupun tidak ada yang terjadi. Aplikasi dapat menjalankan beberapa operasi dan penghitungan dalam satu transaksi.
Menggunakan transaksi
Transaksi adalah kumpulan operasi Datastore pada satu atau beberapa entity. Setiap transaksi dijamin bersifat atomik, yang berarti bahwa transaksi itu tidak pernah diterapkan sebagian. Semua operasi dalam transaksi akan diterapkan, atau tidak ada yang diterapkan. Transaksi memiliki durasi maksimum 60 detik dengan masa berlaku tidak ada aktivitas selama 10 detik setelah 30 detik.
Operasi mungkin gagal jika:
- Terlalu banyak perubahan serentak yang dicoba di entity group yang sama.
- Transaksi melebihi batas resource.
- Datastore mengalami error internal.
Dalam semua kasus ini, Datastore API akan menampilkan error.
Transaksi adalah fitur opsional Datastore; Anda tidak perlu menggunakan transaksi untuk melakukan operasi Datastore.
Fungsi datastore.RunInTransaction
menjalankan fungsi yang disediakan dalam
transaksi.
Jika fungsi menampilkan nil
, RunInTransaction
akan mencoba meng-commit
transaksi, dan menampilkan nil
jika berhasil. Jika fungsi menampilkan nilai error non-nil
,
perubahan Datastore tidak akan diterapkan dan
RunInTransaction
akan menampilkan error yang sama.
Jika tidak dapat meng-commit transaksi karena konflik,
RunInTransaction
akan mencoba lagi, dan akan menyerah setelah tiga kali percobaan. Ini berarti bahwa fungsi transaksi
harus bersifat idempoten, yang berarti keduanya memiliki hasil yang sama ketika
dijalankan beberapa kali. Perhatikan bahwa datastore.Get
tidak idempoten saat
membatalkan marshaling kolom slice.
Yang dapat dilakukan dalam transaksi
Datastore memberlakukan pembatasan pada apa yang dapat dilakukan di dalam satu transaksi.
Semua operasi Datastore dalam transaksi harus beroperasi di entity dalam entity group jika transaksi merupakan transaksi satu grup, atau di entitas dalam maksimum dua puluh lima entity group jika transaksi merupakan transaksi lintas grup. Ini termasuk membuat kueri untuk entity berdasarkan ancestor, mengambil entity berdasarkan kunci, mengupdate entity, dan menghapus entity. Perhatikan bahwa setiap root entity adalah milik entity group terpisah, sehingga satu transaksi tidak dapat membuat atau beroperasi di lebih dari satu root entity kecuali jika merupakan transaksi lintas grup.
Jika dua atau beberapa transaksi secara bersamaan mencoba mengubah entity dalam satu atau beberapa entity group umum, hanya transaksi pertama yang meng-commit perubahannya yang dapat berhasil; sementara yang lain akan gagal saat commit. Karena desain ini, penggunaan entity group akan membatasi jumlah operasi tulis serentak yang dapat Anda lakukan pada entity mana pun dalam grup. Saat transaksi dimulai, Datastore menggunakan kontrol konkurensi optimis dengan memeriksa waktu update terakhir untuk entity group yang digunakan dalam transaksi. Setelah melakukan transaksi untuk entity group, Datastore kembali memeriksa waktu pembaruan terakhir untuk entity group yang digunakan dalam transaksi. Jika terjadi perubahan sejak pemeriksaan awal, error akan ditampilkan.
Isolasi dan konsistensi
Di luar transaksi, tingkat isolasi Datastore itu paling dekat dengan batas baca yang di-commit. Di dalam transaksi, isolasi yang dapat di-serialisasi akan diterapkan. Artinya, transaksi lain tidak dapat mengubah secara serentak data yang dibaca atau diubah oleh transaksi ini.
Dalam transaksi, semua operasi baca mencerminkan status terbaru dan konsisten Datastore pada saat transaksi dimulai. Kueri dan aktivitas yang ada di dalam transaksi dijamin akan melihat satu snapshot Datastore yang konsisten sejak awal transaksi. Entity dan baris indeks dalam entity group transaksi diperbarui sepenuhnya sehingga kueri menampilkan kumpulan entity hasil yang lengkap dan benar, tanpa positif palsu (PP) atau negatif palsu (NP) yang dapat terjadi dalam kueri di luar transaksi.
Tampilan snapshot yang konsisten ini juga meluas ke operasi baca setelah operasi tulis di dalam transaksi. Tidak seperti kebanyakan database, kueri dan get di dalam transaksi Datastore tidak melihat hasil penulisan sebelumnya di dalam transaksi tersebut. Khususnya, jika suatu entity diubah atau dihapus dalam transaksi, kueri atau get akan menampilkan versi asli entity tersebut sejak awal transaksi, atau tidak sama sekali jika entity tersebut belum ada pada saat itu.
Penggunaan transaksi
Contoh ini menunjukkan salah satu penggunaan transaksi: memperbarui entity dengan nilai properti baru yang relatif terhadap nilainya saat ini.
Tindakan ini memerlukan transaksi karena nilai mungkin diperbarui oleh pengguna lain setelah kode ini mengambil objek, tetapi sebelum menyimpan objek yang diubah.
Tanpa transaksi, permintaan pengguna akan menggunakan nilai count
sebelum diupdate pengguna lain, dan penyimpanan akan menimpa nilai baru. Dengan transaksi, aplikasi diberi tahu tentang update pengguna dari lain.
Jika entitas diperbarui selama transaksi, transaksi tersebut akan dicoba lagi hingga semua langkah selesai tanpa gangguan.
Penggunaan umum lainnya untuk transaksi adalah mengambil entity dengan kunci bernama, atau membuatnya jika belum ada:
Seperti sebelumnya, transaksi diperlukan untuk menangani kasus saat pengguna lain mencoba membuat atau memperbarui entity dengan ID string yang sama. Tanpa transaksi, jika entity tidak ada dan dua pengguna mencoba untuk membuatnya, yang kedua akan menimpa entity pertama tanpa menyadarinya.
Jika transaksi gagal, Anda dapat meminta aplikasi mencoba kembali transaksi tersebut hingga berhasil, atau membiarkan pengguna menangani error dengan menyebarkannya ke level antarmuka pengguna aplikasi. Anda tidak perlu membuat loop percobaan ulang di setiap transaksi.
Terakhir, Anda dapat menggunakan transaksi untuk membaca snapshot yang konsisten dari Datastore. Hal ini dapat berguna saat beberapa operasi baca diperlukan untuk merender halaman atau mengekspor data yang harus konsisten. Jenis transaksi ini sering disebut sebagai transaksi hanya baca, karena tidak melakukan penulisan. Transaksi grup tunggal hanya baca tidak pernah gagal karena perubahan serentak, sehingga Anda tidak perlu menerapkan percobaan ulang jika gagal. Namun, transaksi lintas grup dapat gagal karena perubahan serentak, sehingga transaksi tersebut harus dilakukan percobaan ulang. Melakukan commit dan roll back transaksi hanya baca bersifat tanpa pengoperasian.
Antrean tugas transaksional
Anda dapat mengantrekan tugas sebagai bagian dari transaksi Datastore, sehingga
tugas tersebut hanya diantrekan—dan dijamin diantrekan—jika transaksi
berhasil di-commit. Setelah diantrekan, tugas tidak dijamin akan segera
dieksekusi, sehingga tugas tersebut tidak bersifat atomik dengan transaksi. Namun, setelah
diantrekan, tugas akan dicoba lagi hingga berhasil. Hal ini berlaku untuk setiap tugas
yang diantrekan selama fungsi RunInTransaction
.
Tugas transaksional berguna karena memungkinkan Anda menggabungkan tindakan non-Datastore ke transaksi yang bergantung pada keberhasilan transaksi (seperti mengirim email untuk mengonfirmasi pembelian). Anda juga dapat mengaitkan tindakan Datastore ke transaksi, misalnya untuk melakukan perubahan pada entity group di luar transaksi jika dan hanya jika transaksi berhasil.
Aplikasi tidak dapat memasukkan lebih dari lima tugas transaksional ke dalam task queue selama satu transaksi. Tugas transaksi tidak boleh memiliki nama yang ditentukan pengguna.