आपके विकल्प हैं:
-
SERIALIZABLE
में चलाएं एकांत। क्रमांकन विफलता होने के कारण अन्योन्याश्रित लेनदेन को कमिट पर निरस्त कर दिया जाएगा। आपको बहुत से त्रुटि लॉग स्पैम प्राप्त होंगे, और आप बहुत से पुनः प्रयास कर रहे होंगे, लेकिन यह मज़बूती से काम करेगा। -
एक
UNIQUE
परिभाषित करें जैसा कि आपने नोट किया, बाधा और विफलता पर पुनः प्रयास करें। ऊपर के समान मुद्दे। -
यदि कोई मूल वस्तु है, तो आप
SELECT ... FOR UPDATE
. कर सकते हैं अपनाmax
. करने से पहले मूल वस्तु सवाल। इस मामले में आपSELECT 1 FROM bar WHERE bar_id = $1 FOR UPDATE
. आपbar
का उपयोग कर रहे हैं सभी के लिए लॉक के रूप मेंfoo
उसके साथbar_id
. तब आप जान सकते हैं कि आगे बढ़ना सुरक्षित है, जब तक कि हर क्वेरी जो आपके काउंटर इंक्रीमेंट कर रही है, यह मज़बूती से करती है। यह काफी अच्छा काम कर सकता है।यह अभी भी प्रत्येक कॉल के लिए एक समग्र क्वेरी करता है, जो (प्रति अगला विकल्प) अनावश्यक है, लेकिन कम से कम यह उपरोक्त विकल्पों की तरह त्रुटि लॉग को स्पैम नहीं करता है।
-
काउंटर टेबल का प्रयोग करें। मैं यही करूँगा। या तो
bar
. में , या साइड-टेबल जैसेbar_foo_counter
. में , उपयोग करके एक पंक्ति आईडी प्राप्त करेंUPDATE bar_foo_counter SET counter = counter + 1 WHERE bar_id = $1 RETURNING counter
या कम कुशल विकल्प यदि आपका ढांचा
RETURNING
. को संभाल नहीं सकता है :SELECT counter FROM bar_foo_counter WHERE bar_id = $1 FOR UPDATE; UPDATE bar_foo_counter SET counter = $1;
फिर, उसी लेन-देन में ,
number
. के लिए जेनरेट की गई काउंटर पंक्ति का उपयोग करें . जब आप कमिट करते हैं, तो उसbar_id
. के लिए काउंटर टेबल रो अगली क्वेरी के उपयोग के लिए अनलॉक हो जाता है। यदि आप वापस रोल करते हैं, तो परिवर्तन को छोड़ दिया जाता है।
मैं bar
. में कॉलम जोड़ने के बजाय काउंटर के लिए एक समर्पित साइड टेबल का उपयोग करके काउंटर दृष्टिकोण की अनुशंसा करता हूं . यह मॉडल के लिए क्लीनर है, और इसका मतलब है कि आप bar
. में कम अपडेट ब्लोट बनाते हैं , जो क्वेरी को bar
. तक धीमा कर सकता है ।