閱讀141 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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

  上一篇:go 阿裏雲服務器CentOS7啟動tomcat7巨慢
  下一篇:go 關於golang中下劃線(_)的語義說明