Jon*_*ins 5 sql firebird triggers generator auto-increment
检查这段使用生成器的简单代码,在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!
Run Code Online (Sandbox Code Playgroud)
此触发器抓取并增加然后为预订项ID分配生成的值,从而为BOOKING_ITEM表创建自动递增的密钥.触发器甚至检查尚未为预订ID分配值.
问题是如果由于某种原因无法发布BOOKING_ITEM记录,则自动递增的值将丢失(浪费).
关于如何避免这种浪费,我有几点想法,但对每一个都有顾虑.他们来了:
如果发生发布错误,请减少计数器.在触发器中,我设置了一个try-except块(在Firebird PSQL中是否存在try-except块?)并运行一个SELECT GEN_ID(LastIdBookingItem, -1) FROM RDB$DATABASEon post exception.这会有用吗?如果另一个交易在我减少之前潜入并增加发电机怎么办?这真的搞砸了.
使用临时ID.将id设置为某个唯一的临时值,我将其更改为触发器AFTER INSERT时所需的生成器值.这种方法感觉有点人为,需要一种方法来确保temp id是唯一的.但是如果在客户端提供了booking_item_id,我该如何区分它与临时ID?另外我需要另一个触发器
使用交易控制.这与选项1类似.除了使用try-except块重置生成器之外,我启动一个事务,然后在记录无法发布时将其回滚.我不知道使用事务控制的语法.我以为我在某处读过PSQL中不允许SAVEPOINT/SET TRANSACTION.此外,回滚必须在AFTER INSERT触发器中发生,所以我再次需要另一个触发器.
对于任何想要使用Generators的Firebird开发人员来说,这肯定是一个问题.还有其他想法吗?有什么我想念的吗?
序列在事务控制之外,并且干扰它们以获得"无间隙"数字只会导致麻烦,因为另一个事务可能同时增加序列,导致间隙+重复而不是没有间隙:
序列应该主要用于生成人工主键,你不应该关心间隙的存在:只要数字唯一地标识记录就无关紧要.
如果您需要一个可审计的数字序列,并且要求没有间隙,那么您不应该使用数据库序列来生成它.您可以在创建和提交发票后使用序列来分配数字(以确保它是持久的).没有号码的发票根本就不是最终的.然而,即使在这里,也有机会获得差距,例如,如果在分配发票号和提交之间发生错误或其他故障.
另一种方法可能是使用间隙编号明确创建零发票(标记为已取消/编号丢失),以便审计员知道该发票发生了什么.
根据当地法律和法规,您不应"重复使用"或回收丢失的号码,因为这可能被视为欺诈.
您可能会在"可审计的数字系列"中找到其他想法.这也包含一个使用IBObjects的Delphi项目,但文档本身很好地描述了问题和可能的解决方案.