检查以下使用生成器在Firebird表中创建唯一主键的简单代码:
CREATE OR ALTER TRIGGER ON_BEFOREINSERT_PK_BOOKING_ITEM FOR BOOKING_ITEM BEFORE INSERT POSITION 0
AS
BEGIN
IF ((NEW.booking_item_id IS NULL) OR (NEW.booking_item_id = 0)) THEN BEGIN
SELECT GEN_ID(LastIdBookingItem, 1) FROM RDB$DATABASE INTO :NEW.booking_item_id;
END
END!这个触发器抓取并递增,然后为预订项id分配一个生成的值,从而为BOOKING_ITEM表创建一个自动递增的键。触发器甚至检查预订id是否还没有被分配到一个值。
问题是,如果由于某种原因无法发布BOOKING_ITEM记录,则自动递增的值将丢失(浪费)。
对于如何避免这种浪费,我有几个想法,但我对每一个都有顾虑。下面是它们:
SELECT GEN_ID(LastIdBookingItem, -1) FROM RDB$DATABASE。这个能行吗?如果在我减少生成器之前,另一个事务悄悄地进入并增加生成器,该怎么办?那会把事情搞砸的。当然,对于任何想要使用生成器的Firebird开发人员来说,这都是一个问题。还有其他想法吗?我遗漏了什么吗?
发布于 2014-11-27 08:30:24
序列是事务控制之外的,对它们进行干预以获得“无阻塞”的数字只会带来麻烦,因为另一个事务也可能同时增加序列,从而导致gaps+duplicates而不是空白:
序列应该主要用于生成人工主键,并且您不应该关心空白的存在:只要数字唯一地标识记录,这并不重要。
如果您需要一个可审计的数字序列,并且要求没有空白,那么您不应该使用数据库序列来生成它。在创建和提交发票本身之后,您可以使用一个序列来分配编号(这样就可以确保它是持久化的)。一张没有号码的发票还不是最终的。然而,即使在这里,也有机会获得空白(如在分配发票号和承诺之间发生错误或其他失败)。
另一种方法可能是显式地创建带有空白号的零发票(标记为已取消/号码丢失),以便审计师知道该发票发生了什么。
根据当地的法律和法规,你不应该‘重复使用’或回收丢失的数字,因为这可能被理解为欺诈。
您可能在“可审计的数字系列”中找到其他想法。这也包含一个使用IBObjects的Delphi项目,但是文档本身很好地描述了问题和可能的解决方案。
发布于 2019-11-04 13:05:00
如果您没有使用生成器,而是创建了一个列与生成器数量相同的表,给出了每个列的生成器名称。类似于:
create table generators
(
invoiceNumber integer default 0 not null,
customerId integer default 0 not null,
other generators...
)现在,您有了一个表,在该表中,您可以在事务中使用SQL增加发票号,如下所示:
begin transaction
update generator set invoiceNumber = invoiceNumber + 1 returning invoiceNumber;
insert into invoices set ..........
end transaction. 如果有任何问题,交易将被回滚,连同新的发票号码。我认为序列中不会有更多的空白。
埃尼奥
https://stackoverflow.com/questions/27162024
复制相似问题