【发布时间】:2014-11-02 05:49:09
【问题描述】:
一点背景:
我在 Django 中写了一个函数来获取下一个发票号码,它需要是连续的(不是间隙),所以函数看起来像这样:
def get_next_invoice_number():
"""
Returns the max(invoice_number) + 1 from the payment records
Does NOT pre-allocate number
"""
# TODO ensure this is thread safe
max_num = Payment.objects.aggregate(Max('invoice_number'))['invoice_number__max']
if max_num is not None:
return max_num + 1
return PaymentConfig.min_invoice_number
现在的问题是,这个函数只返回max()+1,在我的生产环境中我有多个 Django 进程,所以如果这个函数被调用两次以进行 2 次不同的付款(在保存第一条记录之前),他们将得到相同的发票号码。
为了缓解这个问题,我可以重写 save() 函数来调用 get_next_invoice_number() 以最小化这些函数调用之间的时间间隔,但问题发生的可能性仍然很小。
所以我想在approve方法中实现一个锁,比如
from multiprocessing import Lock
lock = Lock()
class Payment(models.Model):
def approve(self):
lock.acquire()
try:
self.invoice_number = get_next_invoice_number()
self.save()
except:
pass
finally:
lock.release()
所以我的问题是:
- 这看起来还可以吗?
- 锁是多进程的,线程呢?
更新:
- 正如我的同事所指出的,当它部署到多个服务器时,这将不起作用,锁定将毫无意义。
- 看起来 DB 事务锁定是可行的方法。
【问题讨论】:
-
1.) 为什么需要顺序? 2.) 为什么不能在支票上预先分配发票 ID(即使用数据库的自动增量功能)?这样就不会重复了。
-
@Andy 这是一个商业会计要求发票编号是连续的。
标签: python django multithreading locking multiprocessing