擅长:python、mysql、java
<p>我假设你的主键在某种程度上是自然的,这就是为什么你不能依赖普通的自动增量技术。所以假设这个问题实际上是需要插入的某个唯一列中的一个,这是比较常见的。</p>
<p>如果希望“尝试插入,失败时部分回滚”,可以使用保存点,对于SQLAlchemy,保存点是begin_nested()。下一个rollback()或commit()只作用于该保存点,而不是作用于更大范围的事件。</p>
<p>然而,总的来说,这里的模式只是一个真正应该避免的模式。你真正想在这里做的是三件事之一。一。不要运行处理需要插入的相同密钥的并发作业。2。以某种方式在与和3一起工作的并发密钥上同步作业。使用一些公共服务生成此特定类型的新记录,这些记录由作业共享(或确保在作业运行之前都已设置好)。</p>
<p>如果你仔细想想,2在任何情况下都是高度孤立的。开始两个postgres会话。会议1:</p>
<pre><code>test=> create table foo(id integer primary key);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
CREATE TABLE
test=> begin;
BEGIN
test=> insert into foo (id) values (1);
</code></pre>
<p>会议2:</p>
<pre><code>test=> begin;
BEGIN
test=> insert into foo(id) values(1);
</code></pre>
<p>您将看到的是,会话2块,因为PK#1的行被锁定。我不确定MySQL是否足够聪明,但这是正确的行为。如果您试图插入另一个PK:</p>
<pre><code>^CCancel request sent
ERROR: canceling statement due to user request
test=> rollback;
ROLLBACK
test=> begin;
BEGIN
test=> insert into foo(id) values(2);
INSERT 0 1
test=> \q
</code></pre>
<p>一切进展顺利,没有阻碍。</p>
<p>关键是,如果您正在进行这种PK/UQ争用,那么您的芹菜任务无论如何都要序列化自己,或者至少应该序列化。</p>