TL;DR:Deteksi konflik serializability meningkat secara dramatis di Hal 9.1, jadi tingkatkan.
Sulit untuk mengetahui dari deskripsi Anda apa sebenarnya SQL itu dan mengapa Anda berharap mendapatkan rollback. Sepertinya Anda benar-benar salah memahami isolasi serializable, mungkin berpikir itu menguji semua predikat dengan sempurna, padahal tidak, terutama tidak di Hal 8.4.
SERIALIZABLE
tidak sepenuhnya menjamin bahwa transaksi dijalankan seolah-olah dijalankan secara seri - karena melakukan hal itu akan sangat mahal dari sudut pandang kinerja jika memungkinkan. Ini hanya menyediakan pemeriksaan terbatas. Apa yang diperiksa dan bagaimana variasi dari database ke database dan versi ke versi, jadi Anda perlu membaca dokumen untuk versi database Anda.
Anomali mungkin terjadi, di mana dua transaksi dieksekusi dalam SERIALIZABLE
mode menghasilkan hasil yang berbeda jika transaksi tersebut benar-benar dijalankan secara seri.
Baca dokumentasi tentang isolasi transaksi di Hal. untuk mempelajari lebih lanjut. Perhatikan bahwa SERIALIZABLE
perilaku berubah secara dramatis di Pg 9.1, jadi pastikan untuk membaca versi manual yang sesuai untuk versi Pg Anda. Ini versi 8.4
. Secara khusus baca 13.2.2.1. Isolasi Serializable versus Serializability Sejati
. Sekarang bandingkan dengan dukungan serialisasi berbasis penguncian predikat yang sangat ditingkatkan dijelaskan dalam Hal 9.1 dokumen
.
Sepertinya Anda mencoba menjalankan logika seperti kodesemu ini:
count = query("SELECT count(*) FROM the_table");
if (count < threshold):
query("INSERT INTO the_table (...) VALUES (...)");
Jika demikian, itu tidak akan berfungsi di Hal 8.4 saat dijalankan secara bersamaan - itu hampir sama dengan contoh anomali yang digunakan dalam dokumentasi yang ditautkan di atas. Hebatnya itu benar-benar berfungsi pada Hal 9.1; Saya tidak menyangka bahkan penguncian predikat 9.1 akan menangkap penggunaan agregat.
Anda menulis bahwa:
tetapi 8.4 tidak akan mendeteksi bahwa kedua transaksi tersebut saling bergantung, sesuatu yang sepele dapat Anda buktikan dengan menggunakan dua psql
sesi untuk mengujinya. Hanya dengan hal-hal yang benar-serializability yang diperkenalkan di 9.1 ini akan berhasil - dan sejujurnya, saya terkejut itu bekerja di 9.1.
Jika Anda ingin melakukan sesuatu seperti memberlakukan jumlah baris maksimum di Hal 8.4, Anda perlu LOCK
meja
untuk mencegah INSERT
concurrent s, melakukan penguncian baik secara manual atau melalui fungsi pemicu . Melakukannya di pemicu secara inheren akan membutuhkan promosi kunci dan dengan demikian akan sering menemui jalan buntu, tetapi akan berhasil melakukan pekerjaan itu. Lebih baik dilakukan di aplikasi tempat Anda dapat mengeluarkan LOCK TABLE my_table IN EXCLUSIVE MODE
bahkan sebelum mendapatkan SELECT
ing dari tabel, sehingga sudah memiliki mode kunci tertinggi yang dibutuhkan di atas meja dan dengan demikian tidak perlu promosi kunci rawan kebuntuan. EXCLUSIVE
mode kunci sesuai karena memungkinkan SELECT
s tapi tidak ada yang lain.
Berikut cara mengujinya dalam dua sesi psql:
SESSION 1 SESSION 2
create table ser_test( x text );
BEGIN TRANSACTION
ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION
ISOLATION LEVEL SERIALIZABLE;
SELECT count(*) FROM ser_test ;
SELECT count(*) FROM ser_test ;
INSERT INTO ser_test(x) VALUES ('bob');
INSERT INTO ser_test(x) VALUES ('bob');
COMMIT;
COMMIT;
Saat dijalankan pada Hal 9.1, komit st commits succeeds then the second
COMMIT` gagal dengan:
regress=# COMMIT;
ERROR: could not serialize access due to read/write dependencies among transactions
DETAIL: Reason code: Canceled on identification as a pivot, during commit attempt.
HINT: The transaction might succeed if retried.
tetapi ketika dijalankan pada 8.4 kedua komit berhasil, karena 8.4 tidak memiliki semua kode penguncian predikat untuk serializability yang ditambahkan di 9.1.