9

人们如何在典型的 saas 应用程序中为特定用户生成 auto_incrementing 整数?

例如,特定用户的所有发票的发票编号应该是 auto_incrementing 并且从 1 开始。在这种情况下不能使用 rails id 字段,因为它在所有用户之间共享。

在我的脑海中,我可以计算用户拥有的所有发票,然后加 1,但有人知道更好的解决方案吗?

4

6 回答 6

4

任何关系数据库的典型解决方案都可以是类似的表

user_invoice_numbers (user_id int primary key clustered, last_id int)

以及存储过程或 SQL 查询,例如

update user_invoice_numbers set last_id = last_id + 1 where user_id = @user_id
select last_id from user_invoice_numbers where user_id = @user_id

它适用于用户(如果每个用户有几个同时运行的交易),但不适用于公司(例如当您需要 company_invoice_numbers 时),因为来自同一公司内不同用户的交易可能会相互阻塞,并且会出现性能瓶颈在这个表中。

您应该检查的最重要的功能要求是您的系统是否允许在发票编号方面存在空白。当您使用标准 auto_increment 时,您允许间隙,因为在我知道的大多数数据库中,当您回滚事务时,增加的数字不会被回滚。考虑到这一点,您可以使用以下指南之一来提高性能

1)排除您用于从长期运行的事务中获取新号码的过程。假设插入发票过程是一个长时间运行的事务,具有复杂的服务器端逻辑。在这种情况下,您首先获取一个新 id ,然后在单独的事务中插入新发票。如果最后一个事务将被回滚,则自动编号不会减少。但是user_invoice_numbers不会被长时间锁定,所以很多同时的用户可以同时插入发票

2)不要使用传统的事务数据库来存储每个用户的最后一个id的数据。当您需要维护简单的键和值列表时,有许多小而快的数据库引擎可以为您工作。键/值数据库列表。可能memcached是最受欢迎的。过去,我看到使用 Windows 注册表甚至文件系统实现简单键/值存储的项目。有一个目录,其中每个文件名都是键,每个文件内部都是最后一个 id。而且这种粗略的解决方案还是比使用 SQL 表更好,因为锁的发布和释放非常快,并且不涉及事务范围。

好吧,如果我的优化建议对您的项目来说似乎过于复杂,那么现在就忘记这一点,直到您真正遇到性能问题。在大多数项目中,带有附加表的简单方法会很快工作。

于 2009-07-09T16:29:24.610 回答
2

您可以引入另一个与您的“用户”表关联的表,该表跟踪用户的最新发票编号。但是,读取此值将导致数据库查询,因此您不妨按照您的建议获取用户发票的计数并添加一个。无论哪种方式,它都是数据库命中。

于 2009-07-09T15:49:36.670 回答
2

如果发票号码对于每个用户/客户都是独立的,那么在与用户关联的某些持久存储(例如 DB 记录)中具有“lastInvoice”字段似乎是不可避免的。然而,这可能会导致对“最新”数字的一些争论。

如果我们向用户发送发票 1、2、3 和 5,并且从不向他们发送发票 4,这真的很重要吗?如果可以稍微放宽要求。

如果要求实际上是“每个发票编号必须是唯一的”,那么我们可以查看所有正常的 id 生成技巧,这些技巧可能非常有效。

确保数字是连续的会增加复杂性,是否会增加业务收益?

于 2009-07-09T15:53:33.997 回答
1

我刚刚上传了一个可以解决您需求的 gem(迟到几年总比没有好!):)

https://github.com/alisyed/sequenceid/

于 2011-05-31T08:19:42.760 回答
0

不确定这是否是最佳解决方案,但您可以将最后一个发票 ID 存储在用户上,然后在为该用户创建新发票时使用它来确定下一个 ID。但是这个简单的解决方案可能存在完整性问题,需要小心。

于 2009-07-09T15:47:45.223 回答
0

您真的想以增量格式生成发票 ID 吗?这不会打开安全漏洞吗(如果用户可以猜出发票编号的生成,他们可以在请求中更改它并可能导致信息泄露)。理想情况下,我会随机生成数字(并跟踪使用的数字)。这也可以防止冲突(由于数字是在一个范围内随机分配的,因此减少了冲突的机会)。

于 2009-11-09T07:03:18.513 回答