我知道这听起来很奇怪,但是有什么方法可以在表中的ROLLBACK事件上调用触发器?我正在查看postgresql触发器文档,在表上只有CREATE,UPDATE,DELETE和INSERT事件。
我的要求是在事务ROLLBACK上,我的触发器将从表中选择last_id并重置值为= last_id + 1的表序列;简而言之,我想在回滚时保留序列值。
任何想法和反馈将不胜感激的家伙!
您不能为此使用序列。您需要 所有 插入都必须经过的单个序列化点-否则不能保证“ gapless”属性。您还需要确保不会从该表中删除任何行。
序列化还意味着,只有一个事务可以将行插入到该表中-所有其他插入都必须等待,直到“上一个”插入已提交或回滚为止。
如何实现这一点的一种模式是拥有一张表,其中存储“序列”号。假设我们需要发票号,出于法律原因,发票号必须是无间隙的。
因此,我们首先创建表以保存“当前值”:
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该序列的行现在被锁定,因此没有其他事务可以更新该值。如果调用事务回滚,则对序列计数器的更新也将回滚。如果已提交,则新值将保留。
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');
新号码已生成。然后, 第二个 事务需要等待,直到第一个插入被提交或回滚为止。
正如我所说:此解决方案不可扩展。一点也不。如果该表中有很多插入,它将大大减慢您的应用程序的速度。但是,您不能同时拥有两者:无间隙序列的可伸缩 且 正确的实现。
我也很确定上面的代码没有涵盖某些极端情况。因此,您很有可能仍然存在差距。