我有一个用于发票的SaaS宠物项目。在其中,我希望我的客户以票证编号1001开头。显然,我不能在Postgres中使用简单的auto字段,而不能在值中添加1000,因为我的所有客户都将共享相同的数据库和相同的tickets表。我尝试使用整数列类型和查询(伪SQL)SELECTLATEST number FROM tickets WHERE client_id = [current clientID]来获取最新的数字,然后使用该数字+1来获取下一个number。问题在于并发性很容易使两张票以这种方式以相同的号码结尾。我需要能够在Django或原始SQL(与使用Bash或其他同类工具相比)中执行此操作的数量。
tickets
SELECTLATEST number FROM tickets WHERE client_id = [current clientID]
+1
number
我不是在寻找一种方法来强迫我的榜样发挥作用。我只是在寻找一种解决方案,该问题需要为每个客户独立增加票证号。
我认为没有解决此问题的“廉价”解决方案。在多用户环境中唯一安全(但不一定快速)的解决方案是拥有一个“计数器”表,每个客户一行。
每笔交易都必须先锁定客户的条目,然后再插入新票证,如下所示:
UPDATE cust_numbers SET current_number = current_number + 1 WHERE cust_id = 42 RETURNING current_number;
一步就能完成三件事
使用该新号码,您现在可以插入新票证。如果提交了事务,它还将释放对cust_numbers表的锁定,因此其他“等待号码”的事务可以继续进行。
cust_numbers
您可以将两个步骤(更新..返回和插入)包装到单个存储的函数中,以便集中进行此操作后的逻辑。您的应用程序只会在select insert_ticket(...)不知道票证号码如何生成的情况下进行调用。
select insert_ticket(...)
您可能还想在客户表上创建一个触发器,以便在创建cust_numbers新客户时自动在表中插入一行。
这样做的缺点是,您可以有效地序列化为同一客户插入新票证的交易。根据系统中插入内容的数量,这可能会成为性能问题。
编辑这样做的 另一个缺点是,您不会 被迫 以这种方式插入票证,如果新开发者忘记了此票证,可能会导致问题。