【发布时间】:2015-06-04 16:09:35
【问题描述】:
我开始使用 PostgreSQL 并注意到 sequences 永远不会回滚,即使在失败的 INSERT 上也是如此。
我已经读到它可以防止并发事务中的重复序列,我发现这很奇怪,因为我的数据库经验仅适用于GTM,其中事务重新启动很常见并且正好用于此目的。
所以我想在 PGSQL 中测试重启并将其加载到数据库中:
CREATE SEQUENCE account_id_seq;
CREATE TABLE account
(
id integer NOT NULL DEFAULT nextval('account_id_seq'),
title character varying(40) NOT NULL,
balance integer NOT NULL DEFAULT 0,
CONSTRAINT account_pkey PRIMARY KEY (id)
);
INSERT INTO account (title) VALUES ('Test Account');
CREATE OR REPLACE FUNCTION mytest() RETURNS integer AS $$
DECLARE
cc integer;
BEGIN
cc := balance from account where id=1;
RAISE NOTICE 'Balance: %', cc;
perform pg_sleep(3);
update account set balance = cc+10 where id=1 RETURNING balance INTO cc;
return cc;
END
$$
LANGUAGE plpgsql;
所以,函数mytest() 将检索余额,等待 3 秒(让我启动另一个进程),然后根据保存的变量更新余额。
我现在直接从 shell 启动 2 次对该函数的调用:
void$ psql -c "select * from account where id=1"
id | title | balance
----+--------------+---------
1 | Test Account | 0
(1 row)
void$ psql -c "select mytest()" & PIDA=$! && psql -c "select mytest()" && wait $PIDA
[1] 3312
NOTICE: Balance: 0
NOTICE: Balance: 0
mytest
--------
10
(1 row)
mytest
--------
10
(1 row)
[1]+ Done psql -c "select mytest()"
void$ psql -c "select * from account where id=1"
id | title | balance
----+--------------+---------
1 | Test Account | 10
(1 row)
我希望余额为 20,而不是 10,因为在处理过程中 balance from account where id=1 的“视图”发生变化时,要提交的最后一个事务应该重新启动...
我读过关于 transaction isolation in official documentation 的内容,在我看来,默认的 read committed 应该精确地强制执行此行为..
我还测试了将隔离级别更改为serializable,然后提交的最后一个事务确实引发异常,但我想知道是否没有任何“事务重启”功能(如我所述)或者我是否错过了什么……
【问题讨论】:
标签: postgresql transactions plpgsql