涉及具有多个表的多个事务的无间隙序列

Posted

技术标签:

【中文标题】涉及具有多个表的多个事务的无间隙序列【英文标题】:Gap-less sequence where multiple transactions with multiple tables are involved 【发布时间】:2014-04-29 22:57:59 【问题描述】:

我有一个要求(根据法律),不同表格上的数字没有间隙。 ID 中可以有孔,但序列中不能有孔。

这是我必须在 C# 代码或数据库(Postgres、MS SQL 和 Oracle)中解决的问题。

这是我的问题:

Start transaction 1

Start transaction 2

Insert row on table "Portfolio" in transaction 1

Get next number in sequence for column Portfolio_Sequence (1)

Insert row on table "Document" in transaction 1

Get next number in sequence for column Document_Sequence (1)

Insert row on table "Portfolio" in transaction 2

Get next number in sequence for column Portfolio_Sequence (2)

Insert row on table "Document" in transaction 2

Get next number in sequence for column Document_Sequence (2)

Problem occurred in transaction 1

Rollback transaction 1

Commit transaction 2

问题:Portfolio_SequenceDocument_Sequence 的序列间隔。

请注意,这是非常简化的,并且每个事务中都包含更多表。

我该如何处理?

我已经看到了一些建议,您可以“锁定”序列直到事务提交或回滚,但是当涉及这么多表和这么复杂的长事务时,这对于系统来说将是一个巨大的停顿。

【问题讨论】:

“id 可以有洞,但序列不能有洞”。嗯,什么? 【参考方案1】:

正如您似乎已经得出的结论,无间隙序列根本无法扩展。要么在发生回滚时冒着丢失值的风险,要么你有一个序列化点会阻止多用户并发事务系统扩展。你不能两者兼得。

我的想法是,后处理操作怎么样,每天,您都有一个在下班时运行的流程,检查差距,并对需要重新编号的任何内容重新编号?

最后一个想法:我不知道你的要求,但是,我知道你说这是“法律规定的”。好吧,问问你自己,在计算机出现之前人们是做什么的?如何满足这个“要求”?假设您有一堆空白表格,右上角预印有“序列”编号?如果有人把咖啡洒在那个表格上会发生什么?那是怎么处理的?您的系统中似乎需要类似的方法来处理它。

希望对您有所帮助。

【讨论】:

+1 用于重新审视需求。我之前处理过“法律要求”的要求,通常通过回到当前负责执行操作的人员并询问他们如何处理某些情况来解决。一个例子是“我们提交了一个空白表格,其中缺少 ID,上面写着 'void' 字样。”。【参考方案2】:

无间隙序列很难获得。我建议改用普通的serial 列。使用窗口函数row_number() 创建一个视图以生成无间隙序列:

CREATE VIEW foo AS
SELECT *, row_number() OVER (ORDER BY serial_col) AS gapless_id
FROM   tbl;

【讨论】:

【参考方案3】:

这个问题原则上是不可能解决的,因为任何事务都可以回滚(错误、超时、死锁、网络错误……)。

有一个连续的争用点。尽量减少争用:尽量减少分配数字的事务。此外,在事务中尽可能晚地分配号码,因为只有在您分配号码时才会出现争用。如果你正在做 1000 毫秒的无竞争工作,然后分配一个数字(占用 10 毫秒),你仍然有 100 的并行度,这已经足够了。

因此,也许您可​​以插入所有带有虚拟序列号的行(您说有很多行),并且只有在事务结束时,您才能快速分配所有真实序列号并更新已写入的行。如果插入比更新多,或者更新比插入快(它们将是这样),或者在插入之间有其他处理或等待交错,这将很有效。

【讨论】:

【参考方案4】:

这里有个思路,应该同时支持高性能和高并发:

    使用高度并发的高速缓存 Oracle 序列为无间隙表行生成哑唯一标识符。将此实体称为 MASTER_TABLE

    对从 MASTER_TABLE 到其他相关详细信息表的所有内部引用完整性使用哑唯一标识符。

    现在,您的无间隙 MASTER_TABLE 序列号可以作为 MASTER_TABLE 上的附加属性实现,并将由与 MASTER_TABLE 行创建分开的进程填充。事实上,无间隙的附加属性应该在 MASTER_TABLE 的第 4 个范式属性表中维护,因此单个后台线程可以随意填充它,而不用担心 MASTER_TABLE 上的任何行锁。

    所有需要在屏幕或报告或其他内容上显示无间隙序列号的查询,都会将 MASTER_TABLE 与无间隙附加属性第 4 范式表连接起来。请注意,只有在后台线程填充了无间隙附加属性第 4 范式表后,才会满足这些连接。

【讨论】:

以上是关于涉及具有多个表的多个事务的无间隙序列的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 4.2 - 多个数据库的事务回滚问题

Redis ServiceStack 使用事务时如何创建多个序列号

无间隙滚动

具有多个事务的mysql查询

Power Query - 无间隙旋转

@Transactional 具有多个事务管理器和多个数据库