Pilihan Anda adalah:
-
Jalankan di
SERIALIZABLEisolasi. Transaksi interdependen akan dibatalkan pada komit karena mengalami kegagalan serialisasi. Anda akan mendapatkan banyak spam log kesalahan, dan Anda akan melakukan banyak percobaan ulang, tetapi ini akan bekerja dengan andal. -
Tentukan
UNIQUEkendala dan coba lagi pada kegagalan, seperti yang Anda catat. Masalah yang sama seperti di atas. -
Jika ada objek induk, Anda dapat
SELECT ... FOR UPDATEobjek induk sebelum melakukanmaxpertanyaan. Dalam hal ini Anda akanSELECT 1 FROM bar WHERE bar_id = $1 FOR UPDATE. Anda menggunakanbarsebagai kunci untuk semuafoos denganbar_iditu . Anda kemudian dapat mengetahui bahwa aman untuk melanjutkan, selama setiap kueri yang melakukan peningkatan penghitung Anda melakukannya dengan andal. Ini bisa bekerja dengan baik.Ini masih melakukan kueri agregat untuk setiap panggilan, yang (per opsi berikutnya) tidak diperlukan, tetapi setidaknya itu tidak mengirim spam ke log kesalahan seperti opsi di atas.
-
Gunakan meja penghitung. Inilah yang akan saya lakukan. Baik di
bar, atau di tabel samping sepertibar_foo_counter, dapatkan ID baris menggunakanUPDATE bar_foo_counter SET counter = counter + 1 WHERE bar_id = $1 RETURNING counteratau opsi yang kurang efisien jika kerangka kerja Anda tidak dapat menangani
RETURNING:SELECT counter FROM bar_foo_counter WHERE bar_id = $1 FOR UPDATE; UPDATE bar_foo_counter SET counter = $1;Kemudian, dalam transaksi yang sama , gunakan baris penghitung yang dihasilkan untuk
number. Saat Anda melakukan, baris tabel penghitung untukbar_iditu akan dibuka untuk kueri berikutnya untuk digunakan. Jika Anda memutar kembali, perubahan akan dibuang.
Saya merekomendasikan pendekatan penghitung, menggunakan tabel samping khusus untuk penghitung alih-alih menambahkan kolom ke bar . Itu lebih bersih untuk dimodelkan, dan berarti Anda membuat lebih sedikit pembaruan mengasapi di bar , yang dapat memperlambat kueri ke bar .