Transaksi basisdataLink to this heading

Django memberikan anda sedikit cara mengendalikan bagaimana transaksi basisdata dikelola.

Mengelola transaksi basisdataLink to this heading

Kebiasaan transaksi awal DjangoLink to this heading

Kebiasaan awal Django adalah menjalankan suasana penyeraahn otomatis. Setiap query segera diserahkan ke basisdata, meskipun transaksi adalah aktif. Lihat dibawah ini untuk rincian.

Django menggunakan transaksi atau titiksimpan otomatis untuk menjamin kesatuan dari operasi ORM yang membutuhkan banyak query, khususnya query delete() dan update().

Kelas TestCase Django juga membungkus setiap percobaan dalam sebuah transaksi untuk alasan penampilan.

Mengikat transaksi pada permintaan HTTPLink to this heading

Cara umum untuk menangani transaksi di jaringan adalah membungkus setiap permintaan di transaksi. Setel ATOMIC_REQUESTS ke True di konfigurasi dari setiap basisdata untuk anda ingin adakan kebiasaan ini.

Itu bekerja seperti ini. Sebelum memanggil fungsi tampilan, Django memulai sebuah transaksi. Jika tanggapan adalah dihasilkan tanpa masalah, Django melakukan transaksi. Jika tampilan menghasilkan sebuah pengecualian, Django memutar kembali transaksi.

Anda dapat melakukan subtransaksi menggunakan savepoint dalam kode tampilan anda. khususnya dengan pengelola konteks atomic(). Bagaimanapun, pada akhir tampilan, baik semua tau tidak satupun perubahan akan di jalankan.

Dalam praktiknya, fitur ini cukup membungkus setiap fungsi tampilan dalam penghias atomic() digambarkan dibawah.

Catat bahwa hanya penjalanan dari tampilan anda terlampir dalam transaksi, Middleware berjalan diluar transaksi, dan begitu juga membangun tanggapan-tanggapan cetakan.

Ketika ATOMIC_REQUESTS diadakan, itu masih memungkinkan mencegah tampilan dari berjalan dalam sebuah transaksi.

non_atomic_requests(using=None)Link to this definition

Penghias ini akan meniadakan pengaruh dari ATOMIC_REQUESTS untuk tampilan yang diberikan:

Code
from django.db import transaction

@transaction.non_atomic_requests
def my_view(request):
    do_stuff()

@transaction.non_atomic_requests(using='other')
def my_other_view(request):
    do_stuff_on_the_other_database()

Itu hanya bekerja jika itu diberlakukan ke tampilan itu sendiri.

Mengendalikan transaksi secara eksplisitLink to this heading

Django menyediakan API tunggal untuk mengendalikan transaksi basisdata.

atomic(using=None, savepoint=True)Link to this definition

Atomicity adalah penentuan sifat dari transaksi basisdata. atomic mengizinkan kamu membuat blok dari kode dalam yang atomicity pada basisdata dijaminkan. Jika blok dari kode berhasil lengkap, perubahan di perlakukan ke basisdata. Jika ada sebuah pengecualian, perubahan diputar kembali.

Blok atomic dapat bersarang. Dalam kasus ini, ketika sebuah blok sebelah dalam berhasil terpenuhi, pengaruhnya dapat masih di rollback jika sebuah pengecualian dimunculkan di blok sebelah luar pada titik kemudian.

atomic berguna baik sebagai decorator:

Code
from django.db import transaction

@transaction.atomic
def viewfunc(request):
    # This code executes inside a transaction.
    do_stuff()

dan sebagai context manager:

Code
from django.db import transaction

def viewfunc(request):
    # This code executes in autocommit mode (Django's default).
    do_stuff()

    with transaction.atomic():
        # This code executes inside a transaction.
        do_more_stuff()

Membungkus atomic dalam sebuah blok try/except mengizinkan untuk penanganan alami dari kesalahan keutuhan:

Code
from django.db import IntegrityError, transaction

@transaction.atomic
def viewfunc(request):
    create_parent()

    try:
        with transaction.atomic():
            generate_relationships()
    except IntegrityError:
        handle_exception()

    add_children()

Dalam contoh ini, bahkan jika generate_relationships() menyebabkan kesalahan basisdata dengan merusak batasan kesatuan, anda dapat menjalankan permintaan dalam add_children(), dan perubahan dari create_parent() masih disana. Catat bahwa tindakan-tindakan apapun diusahakan dalam generate_relationships() akan sudah diputar kembali dengan aman ketika handle_exception() dipanggil, jadi penangan pengecualian dapat juga berjalan pada basisdata jika dibutuhkan.

Untuk menjamin atomicity, atomic meniadakan beberapa API. Berusaha memperlakukan, memutar kembali, atau merubah keadaan penjalanan otomatis dari hubungan basisdata dalam sebuah blok atomic akan memunculkan sebuah pengecualian.

atomic mengambil sebuah argumen using yang harus berupa nama dari basisdata. Jika argumen ini tidak disediakan, Django menggunakan basisdata "default".

Dibawah tenda, kode pengelolaan transaksi Django:

  • membuka sebuah transaksi ketika memasukkan blok atomic paling luar;

  • membuat titik simpan ketika memasukkan blok atomic sebelah dalam;

  • melepaskan atau digulung kembali ke titik simpan ketika keluar blok paling dalam;

  • menyerahkan atau gulung kembali transaksi ketika keluar blok paling luar

Anda dapat meniadakan pembuatan dari titik simpan untuk blok sebelah dalam dengan mengatur argumen savepoint ke False. Jika sebuah pengecualian muncul, Django akan melakukan gulunh kembali ketika keluar blok induk pertama dengan sebuah titik simpan jika ada, dan blok paling luar jika tidak. Atomicity masih dijamin oleh transaksi paling luar. Pilihan ini harus hanya digunakan jika kelebihan dari titik simpan dapat dilihat. Itu mempunyai kekurangan dari memecahkan penanganan kesalahan yang digambarkan diatas.

Anda dapat menggunakan atomic ketika penyerahan otomatis dimatikan. Itu akan hanya menggunakan titik simpan, bahkan untuk blok paling luar.

Penyerahan otomatisLink to this heading

Kenapa Django menggunakan penyerahan otomatisLink to this heading

Dalam standar SQL, setiap permintaan SQL memulai sebuah transaksi, meskipun satu sudah aktif. Transaksi tersebut harus secara eksplisit diserahkan dan digulung kembali.

Ini tidak selalu mudah untuk pengembang aplikasi. Untuk meredakan masalah ini, kebanyakan basisdata menyediakan sebuah suasana penyerahan otomatis. Ketika penyerahan otomatis dinayalan dan tidak ada transaksi aktif, setiap permintaan SQL dibungkus dalam transaksinya sendiri. Dengan kata lain, bukan hanya melakukan setiap permintaan tersebut mulai sebuah transaksi, tetapi transaksi juga mendapatkan otomatis diserahkan atau digulung kembali, tergandunt pada apakah permintaan berhasil.

PEP 249, Spesifikasi API Basisdata Python v2.0, membutuhkan penjalanan otomatis untuk diawalkan dimatikan. Django menimpa awalan ini dan menyalakan penjalanan otomatis.

Untuk menghindari ini, anda dapat menonaktifkan pengelolaan transaksi, tetapi itu sangat tidak dianjurkan.

Menonaktifkan pengelolaan transaksiLink to this heading

Anda dapat sama sekali meniadakan pengelolaan transaksi Django untuk basis data diberikan dengan mengatur AUTOCOMMIT 1 menjadi False dalam konfigurasinya. Jika anda melakukan ini, Django tidak akan mengadakan autocommit, dan tidak akan melakukan penjalanan apapun. Anda akan mendapatkan perilaku biasa dari pustaka basisdata pokok.

Ini membutuhkan anda untuk menyerahkan secara eksplisit setiap transaksi, bahkan yang dimulai oleh Django atau oleh pustaka pihak ketiga. Jadi, ini adalah penggunaan terbaik dalam keadaan dimana anda ingin menjalankan middleware pengendalian transaksi milik anda atau melakukan sesuatu yang sangat aneh.

Melakukan tindakan setelah penyerahanLink to this heading

Terkadang anda butuh melakukan sebuah tindakan terkait pada transaksi basisdata saat ini, tetapi hanya jika transaksi berhasil diserahkan. Contoh mungkin termasuk tugas Celery, sebuah pemberitahuan surel, atau penghapusan tembolok

Django menyediakan fungsi on_commit() untuk mendaftarkan fungsi panggil kembali yang harusnya dijalankan setelah transaksi berhasil diserahkan:

on_commit(func, using=None)Link to this definition

Lewati fungsi apapun (yang tidak mengambil argumen) ke on_commit():

Code
from django.db import transaction

def do_something():
    pass  # send a mail, invalidate a cache, fire off a Celery task, etc.

transaction.on_commit(do_something)

Anda dapat juga membungkus fungsi anda dalam lambda:

Code
transaction.on_commit(lambda: some_celery_task.delay('arg1'))

Fungsi anda lewati akan dipanggil segera setelah hipotetis penulisan basisdata dibuat dimana on_commit() dipanggil akan berhasil diserahkan.

Jika anda memanggil on_commit() selagi tidak ada sebiah transaksi aktif, panggil kembali akan dijalankan segera.

Jika hipotetis penulisan basisdata itu bukannya digulung kembali (khususnya ketika sebuah pengecualian tidak tertangani dimunculkan dalam sebuah blok atomic()), fungsi anda akan disingkirkan dan tidak pernah dipanggil.

SavepointLink to this heading

Titik simpan (yaitu blok atomic() bersarang) ditangani dengan benar. Yaitu, sebuah on_commit() callable terdaftar setelah sebuah titik simpan (dalam blok atomic() bersarang) akan dipanggil setelah transaksi paling luar diserahkan, tetapi tidak jika disimpan kembali ke titik simpan tersebut atau titik simpan sebelumnya yang muncul selama transaksi:

Code
with transaction.atomic():  # Outer atomic, start a new transaction
    transaction.on_commit(foo)

    with transaction.atomic():  # Inner atomic block, create a savepoint
        transaction.on_commit(bar)

# foo() and then bar() will be called when leaving the outermost block

Pada sisi lain, ketika sebuah titik simpan disimpan kembali (karena sebuah pengecualian telah dimunculkan), sebe;ah dalam dapat dipanggil tidak akan dipanggil:

Code
with transaction.atomic():  # Outer atomic, start a new transaction
    transaction.on_commit(foo)

    try:
        with transaction.atomic():  # Inner atomic block, create a savepoint
            transaction.on_commit(bar)
            raise SomeError()  # Raising an exception - abort the savepoint
    except SomeError:
        pass

# foo() will be called, but not bar()

Urutan pelaksanaanLink to this heading

On-commit functions for a given transaction are executed in the order they were registered.

Penanganan pengecualianLink to this heading

If one on-commit function within a given transaction raises an uncaught exception, no later registered functions in that same transaction will run. This is, of course, the same behavior as if you'd executed the functions sequentially yourself without on_commit().

Waktu pelaksanaanLink to this heading

Gulungan kembali anda dijalankan setelah penyerahan berhasil, jadi sebuah kegagalan dalam gulung kembali tidak akan menyebabkan transaksi di gulung kembali. Mereka dijalankan kondisional atas transaksi berhasil, tetapi mereka bukan bagian dari transaksi. Untuk penggunaan kasus dimaksud (pemberitahuan surat, tugas Celery, dll.), ini harus baik-baik saja. Jika tidak (jika tindakan mengikuti anda juga gawat dimana kegagalan itu harus berarti kegagalan dari transaksi itu sendiri), lalu anda tidak ingin menggunakan hubungan on_commit(). Sebagai gantinya, anda ingin two-phase commit seperti psycopg Two-Phase Commit protocol support dan optional Two-Phase Commit Extensions in the Python DB-API specification.

Callback tidak berjalan sampai perbaikan otomatis dipulihkan pada hubungan perbaikan berikut (karena sebaliknya apapun permintaan selesai dalam sebuah callback akan membuka sebuah transaksi tersirat, mencegah hubungan dari kembali kedalam suasana perbaikan otomatis).

Ketika dalam suasana penjalan otomatis dan diluar dari blok atomic(), fungsi akan berjalan segera tidak pada penjalanan.

On-commit functions only work with autocommit mode and the atomic() (or ATOMIC_REQUESTS) transaction API. Calling on_commit() when autocommit is disabled and you are not within an atomic block will result in an error.

Digunakan dalam percobaanLink to this heading

Django's TestCase class wraps each test in a transaction and rolls back that transaction after each test, in order to provide test isolation. This means that no transaction is ever actually committed, thus your on_commit() callbacks will never be run. If you need to test the results of an on_commit() callback, use a TransactionTestCase instead.

Why no rollback hook?Link to this heading

A rollback hook is harder to implement robustly than a commit hook, since a variety of things can cause an implicit rollback.

Sebagai contoh, jika hubungan basisdata anda jatuh karena pengolahan anda mati tanpa kesempatan dimatikan dengan anggun, hubungan memutar kembali anda tidak pernah berjalan,

Pemecahannya sederhana: daripada melakukan sesuatu selama blok atomic (transaksi) dan kemudian membatalkannya jika transaksi gagal, gunakan on_commit() untuk menunda melakukan itu dalam tempat pertama sampai setelah transaksi berhasil. Itu juga lebih mudah membatalkan sesuatu anda tidak pernah lakukan di tempat pertama.

API tingkat-rendahLink to this heading

Penyerahan otomatisLink to this heading

Django menyediakan API mudah dalam modul django.db.transaction untuk mengelola keadaan penjalan otomatis dari setiap hubungan basisdata.

get_autocommit(using=None)Link to this definition
set_autocommit(autocommit, using=None)Link to this definition

Fungsi-fungsi ini mengambil sebuah argumen using yang harus berupa nama dari basisdata. Jika itu tidak disediakan, Django menggunakan basisdata "default".

Autocommit is initially turned on. If you turn it off, it's your responsibility to restore it.

Once you turn autocommit off, you get the default behavior of your database adapter, and Django won't help you. Although that behavior is specified in PEP 249, implementations of adapters aren't always consistent with one another. Review the documentation of the adapter you're using carefully.

Anda harus memastikan bahwa tidak ada transaksi aktif, biasanya dengan menerbitkan commit() or a rollback(), sebelum menyalakan penjalanan otomatis.

Django akan menolak mematikan autocommit ketika blok atomic()  aktif, karena itu akan merusak atomicity.

TransaksiLink to this heading

Sebuah transaksi adalah atomic kumpulan dari permintaan basisdata. Bahkan jika program anda tabrakan, basisdata menjamin bahwa baik semua perubahan akan diberlakukan, atau tidak dari mereka.

Django tidak menyediakan sebuah API untuk memulai sebuah transaksi. Cara diharapkan memulai sebuah transaksi adalah meniadakan autocommit dengan set_autocommit().

Sekali anda berada dalam transaksi, anda dapat memilih antara memberlakukan perubahan anda telah lakukan sampai titik ini dengan commit(), atau mmebatalkan mereka dengan rollback(). Fungsi-fungsi ini ditentukan dalam django.db.transaction.

commit(using=None)Link to this definition
rollback(using=None)Link to this definition

Fungsi-fungsi ini mengambil sebuah argumen using yang harus berupa nama dari basisdata. Jika itu tidak disediakan, Django menggunakan basisdata "default".

Django menolak commit atau rollback ketika sebuah blok atomic() aktif, karena itu akan merusak atomicity.

SavepointLink to this heading

Sebuah savepoint adalah penanda dalam sebuah transaksi yang mengadakan anda untuk memutar kembali bagian dari transaksi, daripada transaksi penuh. Savepoint tersedia dengan backend SQLite (≥ 3.6.8), PostgreSQL, Oracle dan MySQL (ketika menggunakan mesin penyimpanan InnoDB). Backend-backend lainnya menyediakan fungsi-fungsi savepoint, tetapi mereka adalah tindakan-tindakan kosong -- mereka tidak sebenarnya melakukan apapun.

Savepoint bukanlah khususnya berguna jika anda sedang menggunakan autocommit, perilaku kebiasaan dari Django. Bagaimanapun, sekali anda membuka sebuah transaksi dengan atomic(), anda membangun deretan tindakan-tindakan basisdata menunggu sebuah commit atau rollback. Jika anda menerbitkan sebuah rollback, transaksi keseluruhan diputar kembali yang akan dilakukan dengan transaction.rollback().

Ketika penghias atomic() bersarang, itu membuat sebuah savepoint untuk mengizinkan commit atau rollback sebagian. Anda sangat dianjurkan menggunakan atomic() daripada fungsi-fungsi digambarkan dibawah, tetapi mereka adalah masih bagian dari API umum, dan tidak ada rencana mengusangkan mereka.

Setiap fungsi-fungsi ini mengambil argumen using yang harus dinamai dari basisdata untuk dimana perilaku diberlakukan. Jika tidak ada argumen using disediakan kemudian basisdata "default" digunakan.

Savepoint dikendalikan oleh tiga fungsi dalam django.db.transaction:

savepoint(using=None)Link to this definition

Membuat sebuah savepoint baru. Ini menandai sebuah titik dalam transaksi yang dikenal sebagai keadaan "good". Mengembalikan ID savepoint (sid).

savepoint_commit(sid, using=None)Link to this definition

Bebaskan savepoint sid. Perubahan dilakukan sejak savepoint dibuat menjadi bagian dari transaksi.

savepoint_rollback(sid, using=None)Link to this definition

Memutar kembali transaksi pada savepoint sid.

Fungsi-fungsi ini tidak melakukan apapun jika savepoint tidak didukung atau jika basisdata dalam suasana penjalanan otomatis.

Sebagai tambahan, ada fungsi kegunaan:

clean_savepoints(using=None)Link to this definition

Setel kembali penghitung digunakan untuk membangkitkan ID savepoint unik.

Contoh berikut mempertunjukkan penggunaan dari savepoint:

Code
from django.db import transaction

# open a transaction
@transaction.atomic
def viewfunc(request):

    a.save()
    # transaction now contains a.save()

    sid = transaction.savepoint()

    b.save()
    # transaction now contains a.save() and b.save()

    if want_to_keep_b:
        transaction.savepoint_commit(sid)
        # open transaction still contains a.save() and b.save()
    else:
        transaction.savepoint_rollback(sid)
        # open transaction now contains only a.save()

Savepoint dapat digunakan untuk memulihkan dari kesalahan basisdata dengan melakukan rollback sebagian. Jika anda sedang melakukan ini didalam sebuah blok atomic(), keseluruhan blok akan masih dapat di rollback, karena itu tidak mengetahui anda telah menangani keadaan pada tingkatan terendah! Untuk mencegah ini, anda dapat mengendalikan perilaku rollback dengan fungsi-fungsi berikut.

get_rollback(using=None)Link to this definition
set_rollback(rollback, using=None)Link to this definition

Setel bendera rollback menjadi True memaksa sebuah rollback ketika keluar blok atomik paling sebelah dalam. Ini mungkin berguna untuk memicu sebuah rollback tanpa memunculkan sebuah pengecualian.

Setel itu menjadi False mencegah rollback seperti itu. Sebelum melakukan itu, pastikan anda telah rollback transaksi pada savepoint dikenal-baik dalam blok atomic saat ini! Sebaliknya anda sedang merusak atomic dan kerusakan data mungkin muncul.

Catatan khusus-basisdataLink to this heading

Savepoint di SQLiteLink to this heading

Selagi SQLite ≥ 3.6.8 mendukung savepoint, sebuah cacat dalam perancangan dari modul sqlite3 membuat mereka hampir tidak bisa digunakan.

Ketika autocommit diadakan, savepoint tidak masuk akal. Ketika itu ditiadakan, sqlite3 commit secara mutlak sebelum pernyataan savepoint. (Dalam faktanya, itu commit sebelum pernyataan apapun selain dari SELECT, INSERT, UPDATE, DELETE dan REPLACE.) Kesalahan ini memiliki dua konsekuensi:

  • API tingkat rendah untuk savepoint hanya berguna didalam transaksi yaitu didalam blok atomic().

  • Sangat tidak mungkin menggunakan atomic() ketika penjalan otomatis dimatikan.

Transaksi di MySQLLink to this heading

Jika anda sedang menggunakan MySQL, tabel-tabel anda mungkin atau mungkin tidak mendukung transaksi; itu tergantung pada versi MySQL anda dan jenis-jenis tabel anda sedang gunakan. (Berdasarkan "table types," kami artikan sesuatu seperti "InnoDB" or "MyISAM".) Kekhasan transaksi MySQL adalah diluar cakupan dari artikel ini, tetapi situs MySQL mempunyai information on MySQL transactions.

Jika pengaturan MySQL anda tidak mendukung transaksi, kemudian Django akan selalu menggunakan suasana penjalan otomatis: pernyataan-pernyataan akan dijalankan dan diperlakukan segera mereka dipanggil. Jika pengaturan MySQL anda melakukan mendukung transaksi, Django akan menangani transaksi-transaksi seperti dijelaskan dalam dokumen ini.

Penanganan pengecualian dalam transaksi PostgreSQLLink to this heading

Didalam sebuah transaksi, ketika sebuah panggilan pada kursor PostgreSQL memunculkan sebuah pengecualian (khususnya IntegrityError), semua SQL selanjutnya dalam transaksi sama akan gagal dengan kesalahan "transaksi saat ini dibatalkan, permintaan diabaikan sampai akhir dari blok transakai" Selagi cukup gunakan save() tidak sepertinya memunculkan sebuah pengecualian dalam PostgreSQL, ada pola penggunaan lebih tinggi yang mungkin, seperti menyimpan obyek-obyek dengan bidang-bidang unik, menyimpan menggunakan bendera force_insert/force_update, atau meminta SQL penyesuaian.

Ada beberapa cara memulihkan dari urutan kesalahan ini.

Gulung kembali transaksiLink to this heading

Pilihan pertama adalah memutar kembali transaksi keseluruhan. Sebagai contoh:

Code
a.save() # Succeeds, but may be undone by transaction rollback
try:
    b.save() # Could throw exception
except IntegrityError:
    transaction.rollback()
c.save() # Succeeds, but a.save() may have been undone

Calling transaction.rollback() rolls back the entire transaction. Any uncommitted database operations will be lost. In this example, the changes made by a.save() would be lost, even though that operation raised no error itself.

Memutar kembali savepointLink to this heading

Anda dapat menggunakan savepoints 1 untuk mengendalikan tingkat dari memutar kembali. Sebelum melakukan tindakan basisdata yang dapat gagal, anda dapat menyetel atau memperbaharui savepoint; cara itu, jika tindakan gagal, anda dapat memutar kembali tindakan tunggal menyinggung, daripada transaksi keseluruhan. Sebagai contoh:

Code
a.save() # Succeeds, and never undone by savepoint rollback
sid = transaction.savepoint()
try:
    b.save() # Could throw exception
    transaction.savepoint_commit(sid)
except IntegrityError:
    transaction.savepoint_rollback(sid)
c.save() # Succeeds, and a.save() is never undone

Dalam contoh ini, a.save() tidak akan dilepas dalam kasus dimana b.save() memunculkan sebuah pengecualian.