我在处理并发时遇到了一个问题。
在下面的示例中,两个用户 A 和 B 编辑同一张发票并对其进行不同的更改。如果他们两个同时单击保存,我希望其中一个成功,另一个失败。否则,生成的发票将是不受欢迎的“合并发票”。
这是在 PostgreSQL 中测试的示例(但我认为这个问题应该与数据库无关):
create table invoice (
id int primary key not null,
created date
);
create table invoice_line (
invoice_id int,
line numeric(6),
amount numeric(10,2),
constraint fk_invoice foreign key (invoice_id) references invoice(id)
);
insert into invoice(id, created) values (123, '2018-03-17');
insert into invoice_line (invoice_id, line, amount) values (123, 1, 24);
insert into invoice_line (invoice_id, line, amount) values (123, 2, 26);
所以发票的初始行是:
invoice_id line amount
---------- ---- ------
123 1 24
123 2 26
现在,用户 A 编辑发票,删除第 2 行并点击 SAVE:
-- transaction begins
set transaction isolation level serializable;
select * from invoice where id = 123; -- #1 will it block the other thread?
delete invoice_line where invoice_id = 123 and line = 2;
commit; -- User A would expect the invoice to only include line 1.
同时用户 B 编辑发票并添加第 3 行,然后点击 SAVE:
-- transaction begins
set transaction isolation level serializable;
select * from invoice where id = 123; -- #2 will this wait the other thread?
insert into invoice_line (invoice_id, line, amount) values (123, 3, 45);
commit; -- User B would expect the invoice to include lines 1, 2, and 3.
不幸的是,两个事务都成功了,我得到了合并的行(损坏的状态):
invoice_id line amount
---------- ---- ------
123 1 24
123 3 45
既然这不是我想要的,我有什么选项来控制并发?