【问题标题】:ROLLBACK event triggers in postgresqlpostgresql 中的 ROLLBACK 事件触发器
【发布时间】:2015-11-12 16:08:12
【问题描述】:

我知道这可能听起来很奇怪,但有什么方法可以在表中的 ROLLBACK 事件上调用我的触发器?我正在浏览 postgresql 触发器文档,表上只有 CREATE、UPDATE、DELETE 和 INSERT 的事件。

我的要求是事务 ROLLBACK 我的触发器将从表中选择 last_id 并使用 value = last_id + 1 重置表序列;简而言之,我想在回滚时保留序列值。

任何想法和反馈都将不胜感激!

【问题讨论】:

  • "简而言之,我想在回滚时保留序列值" - 为什么?这听起来完全是浪费时间和资源。如果您真的需要无间隙序列,这绝对不是解决方案。而且如果真的需要无间隙序列(例如出于法律原因)而不是sequence不是正确的工具。
  • 我真的需要无缝序列
  • 如果你真的需要无缝数字,你不能使用序列。
  • 事务中的当前表名”是什么意思 - 一个事务可以访问数百个表。事务中没有“当前表”之类的东西。

标签: sql postgresql triggers transactions


【解决方案1】:

您不能为此使用序列。您需要一个序列化点,all 插入必须通过该点 - 否则无法保证“无缝”属性。您还需要确保不会从该表中删除任何行。

序列化还意味着只有单个事务可以将行插入到该表中 - 所有其他插入必须等到“前一个”插入已提交或回滚。

实现这一点的一种模式是有一个存储“序列”数字的表。假设我们需要这个发票号码,因为法律原因必须是无缝的。

所以我们首先创建表来保存“当前值”:

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');

新号码生成。 第二个事务然后需要等到第一个插入被提交或回滚。


正如我所说:此解决方案不可扩展。一点也不。如果该表中有大量插入,它将大大减慢您的应用程序。但你不能同时拥有:可扩展的无间隙序列的正确实现。

我也很确定上面的代码没有涵盖某些极端情况。所以很有可能你仍然会出现差距。

【讨论】:

  • 是的,我同意,我可能有多个插入,这是不可扩展的。有什么方法可以在事务中获取当前表名? pg_locks 有名为关系的列,但它给出了 OID。如何在事务中检索当前表名?
  • 您可以从 OID 中转换名称,或者直接在 pg_class 中查找。提示:您还想为模式名称加入 pg_namespace。
  • @Vish021:对于无间隙数字的正确解决方案从不可扩展。不可能
  • @a_horse_with_no_name:感谢您的 cmets!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-21
  • 2015-05-28
  • 2011-03-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多