PostgreSQL事务重启
我开始使用PostgreSQL,并注意到,PostgreSQL事务重启,postgresql,transactions,plpgsql,Postgresql,Transactions,Plpgsql,我开始使用PostgreSQL,并注意到,sequences从不回滚,即使在失败的INSERT 我已经读到,正如预期的那样,它可以防止并发事务上的重复序列,我发现这很奇怪,因为我的数据库经验仅限于事务重启是常见的,并且正是用于此目的 所以我想在PGSQL中测试重启,并将其加载到数据库中: CREATE SEQUENCE account_id_seq; CREATE TABLE account ( id integer NOT NULL DEFAULT nextval('account_id
sequence
s从不回滚,即使在失败的INSERT
我已经读到,正如预期的那样,它可以防止并发事务上的重复序列,我发现这很奇怪,因为我的数据库经验仅限于事务重启是常见的,并且正是用于此目的 所以我想在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()
将检索balance,等待3秒钟(让我启动另一个进程),然后根据保存的变量更新balance
现在,我直接从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,因为在处理过程中,账户余额(id=1
的“视图”发生变化时,提交的最后一笔交易应该重新启动
我读过,我觉得默认的readcommitted
应该严格执行此行为。我还测试了将隔离级别更改为可序列化,然后提交的最后一个事务确实会引发异常,但我想知道是否没有任何“事务重新启动”功能(如我所述),或者是否缺少某些内容…如果使用适当的查询,您会自动获得“重新启动”。准确地说,事务不会作为一个整体重新启动,它只是在尝试锁定中的行时等待轮到它: 最近的这些问题似乎也遇到了类似的问题。详细说明和链接:
READ COMMITTED
中遇到锁时那样重新启动查询。相反,它只重新读取锁定的行并继续。请参阅源代码中的EvalPlanQual
,了解一些血淋淋的细节。因此,您实际上可以获得基于重启的方法无法实现的异常。
CREATE OR REPLACE FUNCTION mytest()
RETURNS integer AS
$func$
DECLARE
cc integer;
BEGIN
SELECT INTO cc balance FROM account WHERE id = 1 FOR UPDATE;
RAISE NOTICE 'Balance: %', cc;
PERFORM pg_sleep(3);
UPDATE account SET balance = cc+10
WHERE id = 1
RETURNING balance
INTO cc;
RETURN cc;
END
$func$ LANGUAGE plpgsql;
UPDATE account
SET balance = balance + 10
WHERE id = 1
RETURNING balance;