我有一个 Firebird 生成器的问题,即使我使用
GEN_ID
函数调用它并且将 1 作为增量值调用它,该生成器也会递增超过 1,该生成器在一个存储过程中使用,并且它跟随在另一个存储过程中递增的生成器同样的方式,但是和加一是一致的,这里是存储过程的核心:
create procedure insert_proc (
Type integer)
returns (
Op1 integer,
Op2 integer)
as
begin
if (:Type = 0) then
begin
Op1 = GEN_ID(GEN_OP1, 1);
Op2 = GEN_ID(GEN_OP2, 1);
END
Insert Into Table1(Op1, Op2) VALUES(:Op1, :Op2);
end
该生成器唯一递增 1 的地方是此存储过程与第一个生成器相同,第一个生成器始终递增 1,但第二个生成器有时会使用除示例 6 或 3 以外的值递增。
此过程在同一事务的上下文中调用并正确提交,因为第一个生成器始终是顺序的,但第二个生成器有时会因变量值而关闭。
我还没有尝试任何东西,因为代码是正确的,但似乎我必须缺少一些有关事务级别的信息,或者它可能与数据库或Firebird服务器的版本有关,这就是为什么我需要一些这里有专业知识。
Firebird 生成器不受事务控制,并且存储过程不是原子操作。这意味着如果另一个连接或另一个事务也增加了生成器(例如通过调用相同的存储过程),则可以交错生成值。
也就是说,对于两个事务 T1 和 T2,可能存在多种操作顺序:
T1: Op1 = GEN_ID(GEN_OP1, 1); (T1:OP1 = 1)
T1: Op2 = GEN_ID(GEN_OP2, 1); (T1:OP2 = 1)
T2: Op1 = GEN_ID(GEN_OP1, 1); (T2:OP1 = 2)
T2: Op2 = GEN_ID(GEN_OP2, 1); (T2:OP2 = 2)
T1: Op1 = GEN_ID(GEN_OP1, 1); (T1:OP1 = 1)
T2: Op1 = GEN_ID(GEN_OP1, 1); (T2:OP1 = 2)
T1: Op2 = GEN_ID(GEN_OP2, 1); (T1:OP2 = 1)
T2: Op2 = GEN_ID(GEN_OP2, 1); (T2:OP2 = 2)
T1: Op1 = GEN_ID(GEN_OP1, 1); (T1:OP1 = 1)
T2: Op1 = GEN_ID(GEN_OP1, 1); (T2:OP1 = 2)
T2: Op2 = GEN_ID(GEN_OP2, 1); (T2:OP2 = 1)
T1: Op2 = GEN_ID(GEN_OP2, 1); (T1:OP2 = 2)
T2: Op1 = GEN_ID(GEN_OP1, 1); (T2:OP1 = 1)
T1: Op1 = GEN_ID(GEN_OP1, 1); (T1:OP1 = 2)
T2: Op2 = GEN_ID(GEN_OP2, 1); (T2:OP2 = 1)
T1: Op2 = GEN_ID(GEN_OP2, 1); (T1:OP2 = 2)
T2: Op1 = GEN_ID(GEN_OP1, 1); (T2:OP1 = 1)
T2: Op2 = GEN_ID(GEN_OP2, 1); (T2:OP2 = 1)
T1: Op1 = GEN_ID(GEN_OP1, 1); (T1:OP1 = 2)
T1: Op2 = GEN_ID(GEN_OP2, 1); (T1:OP2 = 2)
中间的示例,订单 T1,T2,T2,T1,是为 T1 引入间隙的示例。添加更多并发事务,可能的组合会爆炸,差异可能会增加。
对此没有真正的解决方案,除了您不应该关心它之外,或者您应该始终使用单个生成器,将其增加 2,并将返回值用于一列,并返回值 - 1另一个(但这可能会对您的数据模型产生其他影响,并且基本上表明您不需要两列,只需一列就足够了,所以我不建议这样做)。