Kerangka kerja tidak memiliki cara untuk mengetahui apakah Anda memulai transaksi. Anda bahkan dapat menggunakan $db->query('START TRANSACTION')
yang tidak akan diketahui oleh framework karena tidak mengurai pernyataan SQL yang Anda jalankan.
Intinya adalah bahwa itu adalah tanggung jawab aplikasi untuk melacak apakah Anda sudah memulai transaksi atau belum. Ini bukan sesuatu yang dapat dilakukan oleh framework.
Saya tahu beberapa kerangka kerja mencoba melakukannya, dan melakukan hal-hal cockamamie seperti menghitung berapa kali Anda memulai transaksi, hanya menyelesaikannya ketika Anda telah melakukan komit atau mundur beberapa kali. Tetapi ini benar-benar palsu karena tidak ada fungsi Anda yang dapat mengetahui apakah komit atau rollback benar-benar akan melakukannya, atau jika mereka berada di lapisan bersarang yang lain.
(Bisakah Anda memberi tahu saya bahwa saya telah melakukan diskusi ini beberapa kali? :-)
Pembaruan 1: Mendorong adalah perpustakaan akses database PHP yang mendukung konsep "transaksi batin" yang tidak komit ketika Anda menyuruhnya. Memulai transaksi hanya menambah penghitung, dan komit/kembalikan akan mengurangi penghitung. Di bawah ini adalah kutipan dari utas milis di mana saya menjelaskan beberapa skenario kegagalannya.
Pembaruan 2: DBAL doktrin juga memiliki fitur ini. Mereka menyebutnya Transaction Nesting.
Suka atau tidak, transaksi bersifat "global" dan tidak mematuhi enkapsulasi berorientasi objek.
Skenario masalah #1
Saya memanggil commit()
, apakah perubahan saya sudah dilakukan? Jika saya menjalankan di dalam "transaksi batin" mereka tidak. Kode yang mengelola transaksi luar dapat memilih untuk memutar kembali, dan perubahan saya akan dibuang tanpa sepengetahuan atau kendali saya.
Misalnya:
- Model A:mulai transaksi
- Model A:jalankan beberapa perubahan
- Model B:memulai transaksi (tanpa operasi senyap)
- Model B:jalankan beberapa perubahan
- Model B:komit (tanpa operasi senyap)
- Model A:rollback (membuang perubahan model A dan perubahan model B)
- Model B:WTF!? Apa yang terjadi dengan perubahan saya?
Skenario masalah #2
Transaksi internal mundur, itu bisa membuang perubahan sah yang dibuat oleh transaksi luar. Ketika kontrol dikembalikan ke kode luar, ia percaya bahwa transaksinya masih aktif dan tersedia untuk dilakukan. Dengan tambalan Anda, mereka dapat memanggil commit()
, dan karena transDepth sekarang 0, ia akan secara diam-diam menyetel $transDepth
ke -1 dan mengembalikan nilai true, setelah tidak melakukan apa pun.
Skenario masalah #3
Jika saya memanggil commit()
atau rollback()
ketika tidak ada transaksi yang aktif, setel $transDepth
ke -1. beginTransaction()
berikutnya menaikkan level ke 0, yang berarti transaksi tidak dapat dibatalkan atau dilakukan. Panggilan berikutnya ke commit()
hanya akan mengurangi transaksi menjadi -1 atau lebih jauh, dan Anda tidak akan pernah dapat melakukan sampai Anda melakukan beginTransaction()
berlebihan lainnya untuk menaikkan level lagi.
Pada dasarnya, mencoba mengelola transaksi dalam logika aplikasi tanpa mengizinkan database melakukan pembukuan adalah ide yang sia-sia. Jika Anda memiliki persyaratan untuk dua model untuk menggunakan kontrol transaksi eksplisit dalam satu permintaan aplikasi, maka Anda harus membuka dua koneksi DB, satu untuk setiap model. Kemudian setiap model dapat memiliki transaksi aktifnya sendiri, yang dapat dilakukan atau dibatalkan secara independen satu sama lain.