2009-07-09 71 views
9

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

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

除了我的头顶,我可以计算用户拥有的所有发票,然后添加1,但有谁知道任何更好的解决方案?

回答

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 

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

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

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

2)不要使用传统的事务数据库来为每个用户存储带有最后一个id的数据。当你需要维护简单的键和值列表时,有很多小而快的数据库引擎可以为你工作。 List of Key/Value databases。可能memcached是最受欢迎的。在过去,我看到了使用Windows注册表甚至文件系统实现的简单键/值存储的项目。有一个目录,每个文件名都是关键字,每个文件都是最后一个ID。这个粗略的解决方案仍然比使用SQL表更好,因为锁发布和发布速度非常快,并且不涉及事务范围。

好吧,如果我的优化提议似乎对您的项目过于复杂,那么现在就忘掉它,直到您真正遇到性能问题。在大多数项目中,使用附加表格的简单方法工作速度非常快。

0

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

+0

是否发票ID属性真是一个用户对象上属于?这是一个实用的解决方案,但不是纯粹主义者的解决方案! – 2009-07-09 15:51:29

+0

如果需要为每个用户确定发票号码,那么“latestInvoiceNumberForThisUser”似乎与用户紧密关联。 – djna 2009-07-09 15:55:08

+0

是的,很有争议。 – 2009-07-09 16:15:24

2

您可以引入另一张与您的“用户”表相关联的表,用于跟踪用户最近的发票号码。但是,读取该值将导致数据库查询,因此您可以按照您的建议计算用户的发票数量并添加一个。无论哪种方式,这是一个数据库命中。

2

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

如果我们发送用户发票1,2,3和5,并且从未发送发票 4,它真的很重要吗?如果你可以稍微放松一下。

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

确保数字是有序的增加了复杂性,是否增加了业务收益?

+0

是的,因为它是一个会计应用程序,数字需要是自动递增整数。所以,它也需要非常坚实。 – 2009-07-09 16:29:30

0

您确实想要以增量格式生成发票ID吗?这是否会打开安全漏洞(如果用户可以猜测发票号码生成,他们可以在请求中更改它并可能导致信息泄露)。 我会理想地随机生成数字(并跟踪使用的数字)。这也可以防止碰撞(随着数字在一定范围内随机分配,碰撞的机会减少)。