我希望在 Postgres 10 中有一个 SQL 语句或函数,允许我仅在行数少于一定数量的情况下插入行。
select count(*) from mytable where mykey = 1
--- do the following only if the above is less than 5
insert into mytable (myvalue, mykey) values ('randomvalue', 1)
--- so there are never more than 5 rows in mytable with mykey = 1
像这样的伪代码可以在应用程序中工作吗(对 postgres 服务器的多次往返调用)?
tx = app.tx("start transaction");
count = tx.query("select count(*) from mytable where mykey = 1")
if (count < 5) {
tx.query("insert into mytable (myvalue, mykey) values ('randomvalue', 1)")
}
tx.do("commit")
如果它不起作用,我如何在 Postgres 端执行此操作,所以我只从应用程序中进行一次调用,例如select myinsertfunction('randomvalue', 1)
?
无论是上面的多次往返方式,还是对 postgres 的单次调用,最重要的是,它不可能以插入超过 5 行的方式并行运行。例如,事务 1 和 2 都检查计数是否为 4(小于最大值 5),并同时进行,因此它们最终都会插入 1 行,总共 6 行,而不是最多 5 个。
这个问题被称为幻读 https://www.postgresql.org/docs/8.0/static/transaction-iso.html:
事务重新执行返回满足搜索条件的行集的查询,并发现满足条件的行集由于另一个最近提交的事务而发生了更改。
Try
BEGIN;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
INSERT INTO mytable (myvalue, mykey) SELECT 'randomvalue', 1 WHERE
(SELECT COUNT(*) FROM mytable WHERE mykey = 1) < 5;
END;
事务隔离级别将确保事务仅在计数小于 5 时才会插入值。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)