मैं पाइथन (वास्तव में प्रासंगिक नहीं) और पोस्टग्रेस्क्ल (9.2 यदि प्रासंगिक हो) का उपयोग कर एक साधारण वेब आधारित आरएसएस रीडर को कार्यान्वित कर रहा हूं। डेटाबेस स्कीमा के रूप में निम्नानुसार (आरएसएस प्रारूप के आधार पर) है: जब मैं एक नया चैनल बनाने (और यह भी नवीनीकृत फ़ीड की जानकारी के लिए क्वेरी) मैं फ़ीड का अनुरोधयदि मौजूद नहीं है तो पंक्ति डालें रेस की स्थिति की ओर जाता है?
CREATE TABLE feed_channel
(
id SERIAL PRIMARY KEY,
name TEXT,
link TEXT NOT NULL,
title TEXT
);
CREATE TABLE feed_content
(
id SERIAL PRIMARY KEY,
channel INTEGER REFERENCES feed_channel(id) ON DELETE CASCADE ON UPDATE CASCADE,
guid TEXT UNIQUE NOT NULL,
title TEXT,
link TEXT,
description TEXT,
pubdate TIMESTAMP
);
, feed_channel मेज पर अपने डेटा डालें, चयन नई डाली गई आईडी - या डुप्लिकेट से बचने के लिए मौजूदा - और फिर फीड डेटा को feed_content तालिका में जोड़ें। एक ठेठ परिदृश्य होगा:
- क्वेरी फ़ीड url, हड़पने फ़ीड हेडर और सभी मौजूदा सामग्री
- सम्मिलित feed_channel में फ़ीड हेडर मौजूद नहीं करता है, तो ... पहले से ही मौजूद हैं, मौजूदा आईडी हड़पने
- प्रत्येक फीड आइटम के लिए, संग्रहित चैनल आईडी
के संदर्भ में feed_content तालिका में डालें यह मानक है "डालें यदि पहले से मौजूद नहीं है, लेकिन प्रासंगिक आईडी लौटाएं" समस्या है। इस मैं निम्नलिखित संग्रहीत प्रक्रिया को लागू किया है हल करने के लिए:
CREATE OR REPLACE FUNCTION channel_insert(
p_link feed_channel.link%TYPE,
p_title feed_channel.title%TYPE
) RETURNS feed_channel.id%TYPE AS $$
DECLARE
v_id feed_channel.id%TYPE;
BEGIN
SELECT id
INTO v_id
FROM feed_channel
WHERE link=p_link AND title=p_title
LIMIT 1;
IF v_id IS NULL THEN
INSERT INTO feed_channel(name,link,title)
VALUES (DEFAULT,p_link,p_title)
RETURNING id INTO v_id;
END IF;
RETURN v_id;
END;
$$ LANGUAGE plpgsql;
यह तो कहा जाता है "channel_insert (लिंक, शीर्षक) का चयन करें," मेरे आवेदन से सम्मिलित करने के लिए यदि पहले से मौजूद नहीं है और फिर प्रासंगिक पंक्ति की आईडी वापस लौटाए चाहे वह डाला गया हो या अभी पाया गया हो (ऊपर सूची में चरण 2)।
यह बहुत अच्छा काम करता है!
हालांकि, मैंने हाल ही में यह सोचना शुरू कर दिया कि क्या होगा यदि इस प्रक्रिया को एक ही समय में एक ही तर्क के साथ दो बार निष्पादित किया गया था। मान देता है निम्नलिखित:
- उपयोगकर्ता एक नया चैनल जोड़ने के लिए 1 के प्रयास और इस तरह अमल channel_insert
- कुछ एमएस बाद में, उपयोगकर्ता 2 प्रयत्न ही चैनल जोड़ने के लिए है और यह भी channel_insert
- के लिए उपयोगकर्ता 1 के चेक पर अमल मौजूदा पंक्तियां पूरी होती हैं, लेकिन सम्मिलन पूर्ण होने से पहले, उपयोगकर्ता 2 की जांच पूरी होती है और कहती है कि कोई मौजूदा पंक्तियां नहीं हैं।
क्या यह पोस्टग्रेएसक्यूएल में संभावित दौड़ की स्थिति होगी? ऐसे परिदृश्यों से बचने के लिए इस समस्या को हल करने का सबसे अच्छा तरीका क्या है? क्या पूरे संग्रहित प्रक्रिया को परमाणु रूप से बनाना संभव है, यानी कि इसे एक ही समय में केवल एक बार निष्पादित किया जा सकता है?
एक विकल्प मैंने कोशिश की थी कि वह फ़ील्ड अद्वितीय बनाएं और फिर पहले डालने का प्रयास करें, और यदि अपवाद है, तो इसके बजाय मौजूदा का चयन करें ... यह काम करता है, हालांकि, प्रत्येक प्रयास के लिए सीरियल फील्ड बढ़ेगा, जिससे बहुत कुछ अनुक्रम में अंतराल। मुझे नहीं पता कि यह लंबे समय तक (शायद नहीं) में एक समस्या होगी, लेकिन परेशान करने की तरह। शायद यह पसंदीदा समाधान है?
किसी भी प्रतिक्रिया के लिए धन्यवाद। PostgreSQL जादू का यह स्तर मेरे बाहर है, इसलिए किसी भी प्रतिक्रिया की सराहना की जाएगी।
.com'), पैरामीटर ऑर्डर जारी ('? ए = बी और सी = डी' और'? सी = डी और ए = बी'), आदि –
डुप्लिकेट कुंजी उल्लंघन के मामले में एक plpgsql फ़ंक्शन लूपिंग दौड़ की स्थिति से निपट सकती है सर्वर-साइड और डिफॉल्ट अलगाव स्तर पर, जो * सुरक्षित * एक आम तौर पर * सबसे सस्ता * है: http://stackoverflow.com/questions/15939902/is-select-or-insert-in-a-function-prone-to- दौड़-स्थितियां/15 9 50324 # 15 9 50324 –