先直接來看例子
這個操作(單純insert)就不是冪等(idempotent).
因為要回應相同的結果.
接著先來看一個時常見到的需求.
就是要做insert,但是若有重複,就不要insert.
所以要先做查詢,判斷是否有找到.
很多人會使用一般自己熟悉的程式語言,來寫個function,
使用 if else 把兩道SQL組合起來.
這裡先用 plpgsql 來寫個function.
由上面例子可以看到,使用SQL 搭配函數,十分地靈活好用.
還可以這樣用.
由上面的結果,可以觀察到, 夢乃あいか, 石川澪 是新增,佐山愛是原本有的.
而 newgals 可以是另一個table.
這樣直接使用一道SQL,就完成了!
而不是寫一隻程式,逐筆讀取新值, 然後先做查詢(select),判斷,再insert.
若沒搭配使用 retuning 時, 像MySQL 會有一個 last_insert_id() ,
有的會使用此函數取得PK,然後再次查詢.如此一來,透過迴圈,並多次讀寫,
效率自然不是很好.甚至有的並未使用(不知道)last_insert_id(),就會由外部程式
來產生uuid,並堅持一定只能這樣.
其實若有觀察到,我們上面的例子中,並未使用PK來判斷.而是使用 unique constraint.
雖然已經有達到冪等操作(請看上面的佐山愛),但是還有另一個坎,就是 Race condition.
先來查看文件
按我前往
裡面提到也要參考 The condition names can be any of those shown in Appendix A.
其中有
23505 unique_violation
接著我們來演化一下 function, 建立一個新的好了.
這個新的函數, 利用 exception 來處理 unique_violation,
這樣當有競爭發生時,落後的 process, 就是改做查詢,符合了冪等操作.
另外注意到輸入參數,改為使用 %type 方式,會更加靈活.
有發現到這個函數一開始的查詢部分,跟後面excption 的處理部分,幾乎相同.
換一個說法就是,因為有了 unique constraint, 而函數又能改處理 unique_violation,
所以此函數可以改為 先 insert 吧, 發生 unique_violation 時,就查詢.
就是把原本 else 之後的 block 拿來就可以了.還減少了 declare 部分.
驗證看看
使用 do nothing
建立新的 table, 與 gals1 相同
可以參考呂健誠這篇
按我前往
感謝佐山愛,小島南,河北彩伽諸位.