8

假设我有一个具有唯一字段电子邮件的模型:

class MyModel:

    email = models.EmailField(unique=True)

    def save(self):
        .... # save model

    def clean(self):
        .... # validate model, make sure email doesn't already exist.

通常,如果浏览器提交一个表单,其中 email 是一个已经存在的值,由于模型表单字段验证,它会引发 ValidationError。

如果两个浏览器同时提交相同的电子邮件,其中电子邮件是一个尚不存在的值,则至少有一个请求将通过将一行保存到数据库中而成功。另一个请求,如果它在第一个请求之后到达足够长的时间,将被正常处理 - 引发 ValidationError 表示电子邮件已经存在。但是,如果它几乎与第一个请求同时到达,那么clean()将成功 - 电子邮件还不存在,但在save()执行该方法时,来自第一个请求的行将被保存。在后一种情况下,将引发 IntegrityError,并且服务器将返回内部服务器 500 错误,这是不可取的。

如何防止最后一种情况发生?数据库事务?

4

2 回答 2

2

在这种情况下仅使用 Django 数据库事务是不够的。创建新模型时要做的是将数据库表锁与事务一起使用。但是 Django 还没有用于锁定表的 API,因此您必须使用原始 SQL 为您的数据库执行关于其类型的表锁定。

如果您使用 PostgreSQL,这里是一个完美的例子: http: //www.caktusgroup.com/blog/2009/05/26/explicit-table-locking-with-postgresql-and-django/

如果您在其他数据库下,您将不得不研究如何执行表锁定。

于 2013-08-28T09:10:09.960 回答
1

虽然用例略有不同,但您可能想阅读Alex Martelli 关于“乐观并发”方法的旧答案

于 2013-08-28T09:14:38.913 回答