如何确保无差距和安全的发票编号生成(法律问题)

Aks*_*kar 5 c# mysql concurrency

背景和系统视图

我们在分布式环境中实施了计费系统.有4个终端每个终端每分钟产生大约2张票据.我们使用Mysql作为后端和C#,winforms作为我们的客户端技术.

任何计费系统中最重要的约束是发票号必须是连续的.为此,我运行类似的查询

在伪代码中

let x ="SELECT count(*) from Orders where IsInvoiceGenerated=1 and FinancialYear=val

new invoicenum = x + 1;
Run Code Online (Sandbox Code Playgroud)

问题 一切都运行正常,直到411发票,之后系统突然跳过2张发票并生成发票414.我们调查了系统状态,发现系统没有外部篡改,我们还推断没有人从工作台访问数据库.这是一个重大问题,因为它也有法律后果.

能否请您建议确保帐单号始终保持顺序的最佳方法.

N.B*_*.B. 2

在开始之前,我想向@Grumbler85 道歉 - 你是对的。这个问题困扰了我一段时间,我将尽我所知尽力回答它。

事务和锁定都不是足够的解决方案。

原因:锁不好,因为一旦锁定表,就必须解锁它。解锁可能会失败,我们都知道网络和计算机的不稳定本质。底线是 - 您必须使用 C# 应用程序来发出锁定和解锁。每次生成发票时,您都必须锁定用作计数器的表,强制所有其他 MySQL 会话等待,直到您释放锁。根据我的经验,几天之内您就必须聘请一名管理员,其工作就是释放锁定。

事务还不够好,因为每个事务都对数据快照进行操作(简化解释,可以修改事务隔离级别)。这意味着 1 笔交易可以计算出发票编号必须为 6,而另一笔交易也可以计算出发票编号必须为 6。

您可以做的是使发票编号唯一,这样如果 2 个(或更多)事务尝试插入相同的编号,您将获得其中至少 1 个的例外,从而防止出现间隙,但发票创建失败。

使用 auto_increment 也不是一个选择。Auto_increment只是一个简单的计数器。这意味着 auto_increment 不会“重用”由于某种原因而丢弃的数字 - 原因是发生错误并且无法保存事务,从而有效地使为该记录计算的 auto_increment 丢失。

那么有哪些选择呢?就我个人而言,我会创建一个简单的服务,该服务将按预定义的时间间隔运行,从而更新尚未invoice_number设置的发票。该服务不提供并发访问,并且始终有一个连接处于活动状态,可以处理一组已插入的发票。

确实,有现行法律(在某些国家,例如英国)规定必须有有序的发票编号,我对此也是错误的。资料来源:http ://www.hmrc.gov.uk/vat/managing/charging/vat-invoices.htm并摘录自资料来源:

唯一的发票号码,与上一张发票的号码一致 - 如果您损坏或取消序列编号的发票,您必须保留它,以便在下次增值税检查时向增值税官员出示

最后一个选项是,如果两个或多个交易获取相同的发票编号,您对发票创建失败感到满意,这意味着您必须实施一种重新运行失败交易的方法(这非常简单)。

  • 使发票号码“唯一”效果很好。我们现在要做的是,如果插入发票由于唯一约束而失败,我们会生成新号码并再次插入。该服务选项不可行,因为必须立即生成发票号码。 (2认同)