τα στοιχεία επικοινωνίας μου
Ταχυδρομείο[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Σε ένα περιβάλλον ταυτόχρονης λειτουργίας βάσης δεδομένων, πολλές συναλλαγές που προσπαθούν να ενημερώσουν τα ίδια δεδομένα ταυτόχρονα μπορεί να προκαλέσουν διενέξεις. Η PostgreSQL παρέχει μια σειρά μηχανισμών για τον χειρισμό αυτών των συγκρούσεων ταυτόχρονης ενημέρωσης για τη διασφάλιση της συνέπειας και της ακεραιότητας των δεδομένων.
Ενδέχεται να προκύψουν διενέξεις ταυτόχρονης ενημέρωσης όταν δύο ή περισσότερες συναλλαγές επιχειρούν να τροποποιήσουν την ίδια σειρά δεδομένων ταυτόχρονα. Τα κοινά σενάρια περιλαμβάνουν:
Η PostgreSQL χρησιμοποιεί κυρίως MVCC (Multiversion Concurrency Control) για να χειρίζεται ταυτόχρονες συναλλαγές. Το MVCC επιτρέπει σε μια συναλλαγή να διαβάζει μια έκδοση δεδομένων που πληροί τις απαιτήσεις του επιπέδου απομόνωσης χωρίς να κλειδώνει για να μπλοκάρει τις λειτουργίες ανάγνωσης άλλων συναλλαγών. Ωστόσο, ενδέχεται να προκύψουν διενέξεις κατά τη διάρκεια των λειτουργιών εγγραφής.
Η PostgreSQL χρησιμοποιεί διάφορους τύπους κλειδαριών για τον έλεγχο της ταυτόχρονης πρόσβασης στα δεδομένα. Οι συνήθεις τύποι κλειδαριάς περιλαμβάνουν:
Η ευαισθησία κλειδώματος μπορεί να είναι σε επίπεδο σειράς (Σειρά-Επίπεδο), σε επίπεδο σελίδας (Σελίδα-Επίπεδο) και σε επίπεδο πίνακα (Επίπεδο πίνακα).
Η PostgreSQL υποστηρίζει τέσσερα επίπεδα απομόνωσης συναλλαγών:
Μια απλή προσέγγιση είναι να επαναλάβετε τη συναλλαγή όταν προκύψει μια σύγκρουση. Παραδείγματα είναι τα εξής:
DO
$$
DECLARE
conflict_detected BOOLEAN := FALSE;
BEGIN
LOOP
-- 尝试执行更新操作
UPDATE products SET price = 100 WHERE id = 1;
-- 检查是否有冲突(例如,通过检查受影响的行数)
IF NOT FOUND THEN
conflict_detected := TRUE;
ELSE
EXIT;
END IF;
-- 若有冲突,等待一段时间并重试
IF conflict_detected THEN
PERFORM pg_sleep(1);
END IF;
END LOOP;
END;
$$;
Στο παραπάνω παράδειγμα, εάν η λειτουργία ενημέρωσης δεν επηρεάζει καμία σειρά (που υποδεικνύει ότι ενδέχεται να υπάρχει διένεξη), ορίζεται μια σημαία, αναμένει για ένα χρονικό διάστημα και, στη συνέχεια, προσπαθεί ξανά.
Ο αισιόδοξος έλεγχος συγχρονισμού προϋποθέτει ότι σπάνια συμβαίνουν συγκρούσεις συγχρονισμού. Σε αυτήν τη μέθοδο, η συναλλαγή δεν κλειδώνει κατά την ενημέρωση των δεδομένων, αλλά ελέγχει εάν τα δεδομένα έχουν τροποποιηθεί από άλλες συναλλαγές κατά τη δέσμευση. Εάν δεν υπάρχουν διενέξεις, η συναλλαγή δεσμεύεται με επιτυχία, εάν υπάρχουν διενέξεις, η συναλλαγή επαναφέρεται και επαναλαμβάνεται όπως απαιτείται.
-- 获取数据的初始版本
SELECT price AS original_price FROM products WHERE id = 1;
-- 进行业务处理和修改
UPDATE products SET price = 100 WHERE id = 1 AND price = original_price;
Στο παραπάνω παράδειγμα, η λειτουργία ενημέρωσης επιτυγχάνεται μόνο εάν τα δεδομένα δεν έχουν τροποποιηθεί από άλλες συναλλαγές.
Ο απαισιόδοξος έλεγχος συγχρονισμού υποθέτει ότι είναι πιθανό να προκύψουν συγκρούσεις συγχρονισμού και αποκτά τα απαιτούμενα λουκέτα κατά την εκτέλεση της συναλλαγής για να μπλοκάρει άλλες δυνητικά αντικρουόμενες συναλλαγές.
BEGIN;
-- 获取排他锁
LOCK TABLE products IN SHARE ROW EXCLUSIVE MODE;
-- 进行数据更新
UPDATE products SET price = 100 WHERE id = 1;
COMMIT;
Προσθέστε ένα πεδίο έκδοσης στον πίνακα για να παρακολουθείτε τις αλλαγές στα δεδομένα.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
price DECIMAL(10, 2),
version INT DEFAULT 0
);
Κατά την ενημέρωση δεδομένων, αυξήστε επίσης το πεδίο έκδοσης:
UPDATE products SET price = 100, version = version + 1 WHERE id = 1 AND version = <expected_version>;
Εάν ο αριθμός των σειρών που επηρεάζονται από την ενημέρωση είναι 0, υπάρχει διένεξη επειδή η αναμενόμενη έκδοση δεν συνάδει με την πραγματική έκδοση.
Προσθέστε ένα πεδίο χρονικής σήμανσης σε κάθε σειρά δεδομένων για να καταγράψετε τον τελευταίο χρόνο τροποποίησης των δεδομένων.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
price DECIMAL(10, 2),
last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Κατά την ενημέρωση, ενημερώνετε μόνο δεδομένα με χρονική σήμανση παλαιότερη από τη χρονική σήμανση που διαβάζεται από την τρέχουσα συναλλαγή:
UPDATE products SET price = 100 WHERE id = 1 AND last_modified <= <read_timestamp>;
Ας υποθέσουμε ότι έχουμε ένα σύστημα διαχείρισης αποθεμάτων για ένα ηλεκτρονικό κατάστημα με α inventory
πίνακα για την αποθήκευση ποσοτήτων αποθέματος ειδών.
CREATE TABLE inventory (
product_id INT PRIMARY KEY,
quantity INT,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Τώρα υπάρχουν δύο ταυτόχρονες συναλλαγές:
Συναλλαγή 1:
BEGIN;
SELECT * FROM inventory WHERE product_id = 1;
-- 假设读取到的数量为 10
UPDATE inventory SET quantity = 5 WHERE product_id = 1 AND last_updated <= <read_timestamp>;
COMMIT;
Συναλλαγή 2:
BEGIN;
SELECT * FROM inventory WHERE product_id = 1;
-- 假设也读取到的数量为 10
UPDATE inventory SET quantity = 8 WHERE product_id = 1 AND last_updated <= <read_timestamp>;
COMMIT;
Εάν αυτές οι δύο συναλλαγές εκτελούνται σχεδόν ταυτόχρονα, μπορεί να προκύψει σύγκρουση.
Εάν χρησιμοποιούμε επίλυση διενέξεων βάσει χρονικής σήμανσης:
T1
)。T2
)。Όταν η συναλλαγή 1 επιχειρεί να ενημερώσει, εάν καμία άλλη συναλλαγή δεν έχει τροποποιήσει τα δεδομένα από τότε που τα διάβασε (δηλ. last_updated <= T1
), η ενημέρωση είναι επιτυχής.
Όταν η συναλλαγή 2 προσπαθεί να ενημερώσει, εάν διαπιστώσει ότι τα δεδομένα last_updated
περισσότερο από τοT2
(Δηλώνει ότι τροποποιήθηκε μετά την ανάγνωση της συναλλαγής 2), η ενημέρωση αποτυγχάνει και η συναλλαγή 2 μπορεί να επιλέξει να επαναφέρει και να προσπαθήσει ξανά ή να εκτελέσει άλλη επεξεργασία σύμφωνα με τη λογική της επιχείρησης.
🎉相关推荐