PostgreSQL 使用advisory lock實現行級讀寫堵塞
標簽
PostgreSQL , select for update , 讀寫衝突 , 讀寫堵塞 , advisory lock
背景
PostgreSQL的讀寫是不衝突的,這聽起來是件好事對吧,讀和寫相互不幹擾,可以數據庫提高讀寫並發能力。
但是有些時候,用戶也許想讓讀寫衝突(需求:數據正在被更新或者刪除時,不允許被讀取)。
那麼有方法能實現讀寫衝突嗎?
PostgreSQL提供了一種鎖advisory lock,可以實現讀寫堵塞的功能。
使用advisory lock實現行級讀寫堵塞
1. 創建表,注意使用一個唯一ID(用於advisory lock)
postgres=# create table ad_test(id int8 primary key, info text, crt_time timestamp);
CREATE TABLE
2. 插入測試數據
postgres=# insert into ad_test values (1,'test',now());
INSERT 0 1
3. 會話1,更新某一條記錄
postgres=# begin;
BEGIN
postgres=# update ad_test set info='abc' where id=1;
UPDATE 1
4. 會話2,讀這條記錄
postgres=# select * from ad_test ;
id | info | crt_time
----+------+----------------------------
1 | test | 2017-05-07 15:57:42.201804
(1 row)
使用以上常規的方法,讀寫是不衝突的。
5. 會話1,更新這條記錄的同時,使用advisory lock鎖住這個ID
postgres=# begin;
BEGIN
postgres=# update ad_test set info='abc' where id=1 returning pg_try_advisory_xact_lock(id);
pg_try_advisory_xact_lock
---------------------------
t
(1 row)
UPDATE 1
6. 會話2,查詢這條記錄時,使用advisory lock探測這條記錄,如果無法加鎖,返回0條記錄。從而實現讀寫堵塞(實際上是隔離)。
postgres=# select * from ad_test where id=1 and pg_try_advisory_xact_lock(1);
id | info | crt_time
----+------+----------
(0 rows)
使用advisory lock,實現了讀寫衝突的需求(實際上是讓讀的會話讀不到被鎖的記錄)。
adlock使用注意
advisory lock鎖住的ID,是庫級衝突的,所以使用時也需要注意喲。
advisory lock相關函數API的詳細介紹
https://www.postgresql.org/docs/9.6/static/explicit-locking.html
https://www.postgresql.org/docs/9.6/static/functions-admin.html
advisory lock的其他應用
1. 《PostgreSQL upsert功能(insert on conflict do)的用法》
2. 《PostgreSQL 無縫自增ID的實現 - by advisory lock》
3. 《PostgreSQL 使用advisory lock或skip locked消除行鎖衝突, 提高幾十倍並發更新效率》
4. 《聊一聊雙十一背後的技術 - 不一樣的秒殺技術, 裸秒》
最後更新:2017-05-08 17:31:00