informasi kontak saya
Surat[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Dalam lingkungan operasi database bersamaan, beberapa transaksi yang mencoba memperbarui data yang sama pada saat yang sama dapat menyebabkan konflik. PostgreSQL menyediakan serangkaian mekanisme untuk menangani konflik pembaruan bersamaan ini untuk memastikan konsistensi dan integritas data.
Konflik pembaruan serentak dapat terjadi ketika dua atau lebih transaksi mencoba mengubah baris data yang sama pada waktu yang sama. Skenario umum meliputi:
PostgreSQL terutama menggunakan MVCC (Multiversion Concurrency Control) untuk menangani transaksi bersamaan. MVCC memungkinkan transaksi membaca versi data yang memenuhi persyaratan tingkat isolasi tanpa mengunci untuk memblokir operasi baca transaksi lainnya. Namun, konflik mungkin masih terjadi selama operasi penulisan.
PostgreSQL menggunakan beberapa jenis kunci untuk mengontrol akses bersamaan ke data. Jenis kunci yang umum meliputi:
Perincian kunci dapat berupa tingkat baris (Tingkat Baris), tingkat halaman (Tingkat Halaman), dan tingkat tabel (Tingkat Tabel).
PostgreSQL mendukung empat tingkat isolasi transaksi:
Pendekatan sederhananya adalah dengan mencoba ulang transaksi ketika terjadi konflik. Contohnya adalah sebagai berikut:
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;
$$;
Dalam contoh di atas, jika operasi pembaruan tidak mempengaruhi baris apa pun (menunjukkan bahwa mungkin ada konflik), sebuah tanda disetel, menunggu selama jangka waktu tertentu, lalu mencoba lagi.
Pengendalian konkurensi optimis mengasumsikan bahwa konflik konkurensi jarang terjadi. Dalam metode ini, transaksi tidak dikunci saat memperbarui data, tetapi memeriksa apakah data telah diubah oleh transaksi lain saat dilakukan. Jika tidak ada konflik, transaksi berhasil dilakukan; jika ada konflik, transaksi dibatalkan dan dicoba lagi sesuai kebutuhan.
-- 获取数据的初始版本
SELECT price AS original_price FROM products WHERE id = 1;
-- 进行业务处理和修改
UPDATE products SET price = 100 WHERE id = 1 AND price = original_price;
Dalam contoh di atas, operasi pembaruan hanya berhasil jika data belum diubah oleh transaksi lain.
Kontrol konkurensi pesimistis mengasumsikan bahwa konflik konkurensi mungkin terjadi, dan memperoleh kunci yang diperlukan selama eksekusi transaksi untuk memblokir transaksi lain yang berpotensi menimbulkan konflik.
BEGIN;
-- 获取排他锁
LOCK TABLE products IN SHARE ROW EXCLUSIVE MODE;
-- 进行数据更新
UPDATE products SET price = 100 WHERE id = 1;
COMMIT;
Tambahkan bidang versi ke tabel untuk melacak perubahan pada data.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
price DECIMAL(10, 2),
version INT DEFAULT 0
);
Saat memperbarui data, tambah juga kolom versi:
UPDATE products SET price = 100, version = version + 1 WHERE id = 1 AND version = <expected_version>;
Jika jumlah baris yang terpengaruh oleh pembaruan adalah 0, terjadi konflik karena versi yang diharapkan tidak konsisten dengan versi sebenarnya.
Tambahkan bidang stempel waktu ke setiap baris data untuk mencatat waktu modifikasi terakhir data.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
price DECIMAL(10, 2),
last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Saat memperbarui, hanya perbarui data dengan stempel waktu yang lebih lama dari stempel waktu yang dibaca oleh transaksi saat ini:
UPDATE products SET price = 100 WHERE id = 1 AND last_modified <= <read_timestamp>;
Misalkan kita memiliki sistem manajemen inventaris untuk toko online dengan a inventory
meja untuk menyimpan jumlah persediaan barang.
CREATE TABLE inventory (
product_id INT PRIMARY KEY,
quantity INT,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Sekarang ada dua transaksi bersamaan:
Transaksi 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;
Transaksi 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;
Jika kedua transaksi ini dijalankan pada waktu yang hampir bersamaan, konflik dapat terjadi.
Jika kami menggunakan resolusi konflik berdasarkan stempel waktu:
T1
)。T2
)。Ketika transaksi 1 mencoba memperbarui, jika tidak ada transaksi lain yang mengubah data sejak transaksi tersebut membacanya (yaitu last_updated <= T1
), pembaruan berhasil.
Ketika transaksi 2 mencoba memperbarui, jika menemukan data itu last_updated
lebih dari ituT2
(Menunjukkan bahwa itu diubah setelah transaksi 2 membacanya), pembaruan gagal, dan transaksi 2 dapat memilih untuk memutar kembali dan mencoba lagi, atau melakukan pemrosesan lain sesuai dengan logika bisnis.
🎉相关推荐