繁体   English   中英

SQL:更新列计数器并插入新行

[英]SQL: update column counter and insert new row

我有两个表(这是我的用例的非常简化的模型):

- TableCounter with 2 columns: idEntry, counter
- TableObject with 1 column : idEntry , seq (with the pair idEntry/seq unique)

我需要能够完成1项交易:

- increase counter for idEntry = x
- insert (x,new_counter_value) in the TableObject.

知道我一定不会丢失任何顺序,这是一个高度并发的事务,被称为很多事务。

您将如何在语句中编写这样的事务(不适用于存储过程)? 您会为idEntry = x锁定TableCounter的行吗?

到目前为止,我已经有了,但是我正在寻找更好的解决方案。

BEGIN TRANSACTION;
SELECT counter FROM TableCounter WHERE idEntry=1 FOR UPDATE;
UPDATE TableCounter SET counter=counter+1 WHERE idEntry=1;
INSERT INTO TableObject(idEntry, seq) SELECT  TableCounter.idEntry, TableCounter.counter FROM TableCounter WHERE  TableCounter.idEntry = 1;
COMMIT TRANSACTION 

谢谢

如果您接下来要做的是更新行,则select for update没用(对于任何支持select for update DBMS都是如此)

对于Postgres,可以使用修改CTE的数据在单个语句中完成:

with updated as (
  update tablecounter 
     set counter = counter + 1
  where identry = 1
  returning identry, counter
)
insert into tableobject (identry, seq)
select identry, counter
from updated;

更新将锁定该行,这意味着任何并发的插入/更新(对于同一identry )都必须等待,直到提交或回滚以上内容。


如果我真的需要一个无间隔的序列,并且可以忍受这样一个解决方案的可伸缩性问题(因为要求比性能或可伸缩性更重要),我可能会将其放入函数中。 类似于以下内容:

定义序列(=计数器)表

create table gapless_sequence 
(
   entity text not null primary key,
   sequence_value integer not null default 0
);

-- "create" a new sequence
insert into gapless_sequence (entity) values ('some_table');
commit;

现在创建一个声明新值的函数

create function next_value(p_entity text)
  returns integer
as
$$
  update gapless_sequence
     set sequence_value = sequence_value + 1
  where entity = p_entity
  returning sequence_value;
$$
language sql;

与上述相同:获取实体下一个序列的事务将阻止对该实体的该函数的所有后续调用,直到提交(或回滚)第一个事务为止。

现在定义使用无间隙序列的表非常容易:

create table some_table
(
   id integer primary key default next_value('some_table'),
   some_column text
);

然后您只需执行以下操作:

insert into some_table (some_column) values ('foo');

some_table并发插入将等待直到第一个事务提交。 然后, update将看到提交的值并返回适当的下一个序列值。

当然,也可以在表定义中不使用default子句来完成此操作,但是您将需要在insert语句中显式调用该函数:

insert into some_table 
  (id, some_column) 
values 
 (next_value('some_table'), 'foo');

但是,这样做有一个潜在的陷阱,那就是在调用函数时,没有什么可以强迫您使用正确的实体名称。


以上所有示例均假定自动提交已关闭

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM