2015-11-12 73 views
0

我知道這可能聽起來很奇怪,但有什麼辦法可以在表中的ROLLBACK事件上調用我的觸發器嗎?我正在通過postgresql觸發器文檔,只有CREATE,UPDATE,DELETE和INSERT表上的事件。postgresql中的ROLLBACK事件觸發器

我的要求是在事務ROLLBACK我的觸發器將從表中選擇last_id並重置表序列值= last_id + 1;總之我想在回滾時保留序列值。

任何類型的想法和反饋將受到讚賞的傢伙!

+1

「*簡而言之,我想在回滾時保留序列值*」 - 爲什麼?這聽起來像是時間和資源的完全浪費。如果你真的**需要無間斷序列,這絕對不是一個解決方案。如果你真的需要無間斷的序列(例如出於合法的原因),而不是'序列'就不是**的正確工具。 –

+0

我真的需要無縫序列 – Vish021

+0

@a_horse_with_no_name或者有沒有什麼辦法在事務中獲取當前表名? – Vish021

回答

3

您無法爲此使用序列。您需要一個序列化點,全部插入必須去 - 否則「無縫」屬性不能保證。您還需要確保從該表中不會刪除任何行。

序列化還意味着只有一個事務可以將行插入到該表中 - 所有其他插入必須等到「先前」插入已被提交或回滾。

一個模式是如何實現的,就是擁有一個存儲「序列」數字的表格。讓我們假設我們需要這樣的發票號碼,由於法律原因,發票號碼必須是無間隙的。

因此,我們首先要創建表來保存「當前值」:

create table slow_sequence 
(
    seq_name  varchar(100) not null primary key, 
    current_value integer not null default 0 
); 

-- create a "sequence" for invoices 
insert into slow_sequence values ('invoice'); 

現在我們需要的是會產生下一個號碼的功能,但它保證沒有兩筆交易可以在獲得下一個數同時。

create or replace function next_number(p_seq_name text) 
    returns integer 
as 
$$ 
    update slow_sequence 
    set current_value = current_value + 1 
    where seq_name = p_seq_name 
    returning current_value; 
$$ 
language sql; 

該函數將遞增計數器並返回遞增的值作爲結果。由於update該序列的行現在被鎖定,並且沒有其他事務可以更新該值。如果調用事務回滾,那麼更新序列計數器。如果它被提交,則新值將被保留。

爲確保事務使用該函數,應該創建一個觸發器。

創建問題的表:

create table invoice 
(
    invoice_number integer not null primary key, 
    customer_id integer not null, 
    due_date  date not null 
); 

現在創建的觸發功能和觸發:現在

create or replace function f_invoice_trigger() 
    returns trigger 
as 
$$ 
begin 
    -- the number is assigned unconditionally so that this can't 
    -- be prevented by supplying a specific number 
    new.invoice_number := next_number('invoice'); 
    return new; 
end; 
$$ 
language plpgsql; 

create trigger invoice_trigger 
    before insert on invoice 
    for each row 
    execute procedure f_invoice_trigger(); 

如果一個交易做到這一點:

insert into invoice (customer_id, due_date) 
values (42, date '2015-12-01'); 

的新號碼生成。 A 事務需要等到第一個插入提交或回滾。


正如我所說:這種解決方案是不可擴展的。一點也不。如果有大量的插入到表中,它會大量減慢你的應用程序。但是,您不能同時擁有:可擴展的正確實現無間隙序列。

我也很確定有邊緣的情況下沒有被上面的代碼覆蓋。所以很可能你仍然可以縮小差距。

+0

是的,我同意,我可能有多個插入,這是不可擴展的。有沒有什麼辦法可以在交易中獲得當前表名? 'pg_locks'具有名爲關係的列,但它提供了OID。我如何檢索交易中的當前表名? – Vish021

+0

您可以從OID中強制轉換名稱,或者只是在pg_class中查找它。提示:您還希望爲模式名稱加入pg_namespace。 –

+5

@ Vish021:無縫數字的*正確*解決方案**從不**可伸縮。它不能是 –