MySQL

2014-06-17 8 views
9

परिदृश्य में ट्रिगर्स और टेबल लॉक: मेरे पास कुछ ट्रिगर्स हैं जो एक उपयोगी तालिका के साथ एक तालिका के रिकॉर्ड की संख्या का ट्रैक रखते हैं। इन ट्रिगर्स को इस तालिका में जोड़ने/हटाने/अपडेट करने पर निकाल दिया जाता है और इस जानकारी को किसी अन्य पूरक तालिका में लिखने का ख्याल रखना पड़ता है।MySQL

अब ये ट्रिगर एक बहु थ्रेडेड वातावरण पर चलेंगे जहां संभवतः मेरे पास तालिकाओं तक समवर्ती पहुंच हो सकती है। मुझे लगता है मैं कुछ इस तरह कर सकता है, लेकिन यह मना किया है

DELIMITER $$ 
DROP TRIGGER IF EXISTS del_alarmCount$$ 
CREATE TRIGGER del_alarmCount AFTER DELETE ON Alarm 
FOR EACH ROW 
BEGIN 
SET autocommit=0; 
LOCK TABLES AlarmCount WRITE, AlarmMembership READ; 
    UPDATE AlarmCount SET num = num - 1 
    WHERE RuleId = OLD.RuleId AND 
     MemberId = 0 AND 
     IsResolved = OLD.IsResolved; 

    UPDATE AlarmCount SET num = num - 1 
    WHERE RuleId = OLD.RuleId AND 
     IsResolved = OLD.IsResolved AND 
     MemberId IN (SELECT MemberId FROM AlarmMembership WHERE AlarmId=OLD.Id); 
COMMIT; 
UNLOCK TABLES; 
END $$ 
DELIMITER ; 

लक्ष्यों इन ताले को प्राप्त करने के लिए (या वैकल्पिक: (त्रुटि: त्रुटि कोड: 1314 लॉक संग्रहित प्रक्रियाओं में अनुमति नहीं है) निर्माणों) कर रहे हैं:

  1. एक साथ चल दो ट्रिगर AlarmCount मेज और अद्यतन संबंधित रिकॉर्ड पर लिखने (मुझे लगता है मैं दो ट्रिगर AlarmCount का एक ही रिकॉर्ड को अपडेट करने) अलार्म तालिका के विभिन्न रिकॉर्ड
  2. सुनिश्चित करें कि लिए चला रहे हों बचें अलार्ममेम्बरशिप तालिका इस दौरान संशोधित नहीं होती है (उदा। लक्ष्य सदस्य आईडी इस बीच हटा दिया जाता है)।

कोई सलाह बहुत स्वागत है!

उत्तर

6

मुझे लगता है कि संभाल करने के लिए सबसे अच्छा तरीका यह चयन का उपयोग किया जाएगा ... अद्यतन पैटर्न यहाँ वर्णित के लिए: http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html

संदर्भ के लिए:

Let us look at another example: We have an integer counter field in a table child_codes that we use to assign a unique identifier to each child added to table child. It is not a good idea to use either consistent read or a shared mode read to read the present value of the counter because two users of the database may then see the same value for the counter, and a duplicate-key error occurs if two users attempt to add children with the same identifier to the table.

Here, LOCK IN SHARE MODE is not a good solution because if two users read the counter at the same time, at least one of them ends up in deadlock when it attempts to update the counter.

To implement reading and incrementing the counter, first perform a locking read of the counter using FOR UPDATE, and then increment the counter. For example:

SELECT counter_field FROM child_codes FOR UPDATE; UPDATE child_codes 
SET counter_field = counter_field + 1; 

A SELECT ... FOR UPDATE reads the latest available data, setting exclusive locks on each row > it reads. Thus, it sets the same locks a searched SQL UPDATE would set on the rows.

। । ।

Note Locking of rows for update using SELECT FOR UPDATE only applies when autocommit is disabled (either by beginning transaction with START TRANSACTION or by setting autocommit to 0. If autocommit is enabled, the rows matching the specification are not locked.

अपने मामले में

तो, आप की जगह लेंगे

LOCK TABLES AlarmCount WRITE, AlarmMembership READ; 
    UPDATE AlarmCount SET num = num - 1 
    WHERE RuleId = OLD.RuleId AND 
     MemberId = 0 AND 
     IsResolved = OLD.IsResolved; 

की तरह कुछ के साथ

SELECT num FROM AlarmCount WHERE RuleId = OLD.RuleId AND 
      MemberId = 0 AND 
      IsResolved = OLD.IsResolved FOR UPDATE; 
UPDATE AlarmCount SET num = num - 1; 

मैं कहता हूँ "की तरह कुछ" क्योंकि यह मेरे लिए पूरी तरह से स्पष्ट नहीं है क्या OLD.RuleId और OLD.IsResolved संदर्भ है। इसके अलावा http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html से ध्यान देने योग्य है:

The preceding description is merely an example of how SELECT ... FOR UPDATE works. In MySQL, the specific task of generating a unique identifier actually can be accomplished using only a single access to the table:

UPDATE child_codes SET counter_field = LAST_INSERT_ID(counter_field + 
1); 
SELECT LAST_INSERT_ID(); 

The SELECT statement merely retrieves the identifier information (specific to the current connection). It does not access any table.

दूसरे शब्दों में, आप शायद इस पद्धति आगे केवल तालिका एक बार पहुंच कर अनुकूलन कर सकते हैं ... लेकिन फिर वहाँ अपने स्कीमा बारे में कुछ जानकारी है कि मैं काफी पालन न करें, और मुझे यकीन नहीं है कि मैं आपको आवश्यक वास्तविक कथन प्रदान कर सकता हूं। मुझे लगता है कि अगर आप एक नजर डालें ... अद्यतन के लिए, हालांकि, आप देखेंगे कि पैटर्न क्या उबलता है, और आपको अपने पर्यावरण में यह काम करने के लिए क्या करना है।

मुझे यह भी उल्लेख करना चाहिए कि कुछ स्टोरेज इंजन पर्यावरण और लेनदेन अलगाव स्तर हैं जिन्हें आप विचार करना चाहते हैं। इस विषय पर SO पर बहुत अच्छी चर्चा है: When to use SELECT ... FOR UPDATE?

आशा है कि इससे मदद मिलती है!

+1

मैंने कॉलर कोड लॉक करना समाप्त कर दिया, इसलिए संभावित संघर्षों को रोकना। लेकिन, बहुत अच्छा समाधान धन्यवाद! मैं अगली बार इस मुद्दे पर विचार करूंगा। – DocDbg