首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何避免在Firebird中使用生成器值时浪费它们的服务器端?

如何避免在Firebird中使用生成器值时浪费它们的服务器端?
EN

Stack Overflow用户
提问于 2014-11-27 02:10:27
回答 2查看 1.1K关注 0票数 5

检查以下使用生成器在Firebird表中创建唯一主键的简单代码:

代码语言:javascript
运行
复制
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记录,则自动递增的值将丢失(浪费)。

对于如何避免这种浪费,我有几个想法,但我对每一个都有顾虑。下面是它们:

  1. 如果发生投递错误,将取消计数器。在触发器中,我设置了一个try--除了块(确实尝试--除了在Firebird PSQL中存在的块?)并对post异常运行SELECT GEN_ID(LastIdBookingItem, -1) FROM RDB$DATABASE。这个能行吗?如果在我减少生成器之前,另一个事务悄悄地进入并增加生成器,该怎么办?那会把事情搞砸的。
  2. 使用临时Id。将id设置为某些唯一的临时值,在插入后将其更改为触发器上希望的生成器值。此方法有些人为设计,需要一种确保临时id是唯一的方法。但是,如果提供了客户端的booking_item_id,我将如何区分它和临时id?另外,我需要另一个扳机
  3. 使用事务控制。这类似于选项1。除了使用try- of块重置生成器之外,我启动了一个事务,然后在记录失败时回滚它。我不知道使用事务控制的语法。我想我在某个地方读到,在PSQL中不允许保存点/SET事务。此外,回滚必须发生在后插入触发器,所以我再次需要另一个触发器。

当然,对于任何想要使用生成器的Firebird开发人员来说,这都是一个问题。还有其他想法吗?我遗漏了什么吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-11-27 08:30:24

序列是事务控制之外的,对它们进行干预以获得“无阻塞”的数字只会带来麻烦,因为另一个事务也可能同时增加序列,从而导致gaps+duplicates而不是空白:

  • 启动:生成器值=1
  • T1:增量:值为2
  • T2:增量:值为3
  • T1:“回滚”,递减:值为2(而不是您预期的1)
  • T3:递增:值为3 =>重复值

序列应该主要用于生成人工主键,并且您不应该关心空白的存在:只要数字唯一地标识记录,这并不重要。

如果您需要一个可审计的数字序列,并且要求没有空白,那么您不应该使用数据库序列来生成它。在创建和提交发票本身之后,您可以使用一个序列来分配编号(这样就可以确保它是持久化的)。一张没有号码的发票还不是最终的。然而,即使在这里,也有机会获得空白(如在分配发票号和承诺之间发生错误或其他失败)。

另一种方法可能是显式地创建带有空白号的零发票(标记为已取消/号码丢失),以便审计师知道该发票发生了什么。

根据当地的法律和法规,你不应该‘重复使用’或回收丢失的数字,因为这可能被理解为欺诈。

您可能在“可审计的数字系列”中找到其他想法。这也包含一个使用IBObjects的Delphi项目,但是文档本身很好地描述了问题和可能的解决方案。

票数 8
EN

Stack Overflow用户

发布于 2019-11-04 13:05:00

如果您没有使用生成器,而是创建了一个列与生成器数量相同的表,给出了每个列的生成器名称。类似于:

代码语言:javascript
运行
复制
create table generators
(
 invoiceNumber  integer default 0 not null,
 customerId     integer default 0 not null,
 other generators...
)

现在,您有了一个表,在该表中,您可以在事务中使用SQL增加发票号,如下所示:

代码语言:javascript
运行
复制
begin transaction
  update generator set invoiceNumber = invoiceNumber + 1 returning invoiceNumber;
  insert into invoices set ..........  
end transaction. 

如果有任何问题,交易将被回滚,连同新的发票号码。我认为序列中不会有更多的空白。

埃尼奥

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27162024

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档