在 PostgreSQL 中(我使用 14 和 16),我试图创建一个函数,将记录插入到具有两列的表中:标识符(整数)和字符串“Some string”。我想编写一个循环来插入 N 条记录,但在每 K 条插入后提交,以便我可以查看另一个会话中发生的情况。我该怎么做呢?到目前为止,我已经尝试了很多选项,都是这个的一些变体:
DROP TABLE IF EXISTS testtable;
CREATE TABLE IF NOT EXISTS testtable
(
identifier bigint NOT NULL,
description character varying(128),
CONSTRAINT testtable_pkey PRIMARY KEY (identifier)
);
CREATE OR REPLACE FUNCTION insert_records(N INT, K INT)
RETURNS VOID AS $$
DECLARE
i INT;
BEGIN
FOR i IN 1..N LOOP
INSERT INTO testtable (identifier, description) VALUES (i, 'some string');
IF MOD(i, K) = 0 THEN
COMMIT;
END IF;
END LOOP;
COMMIT;
END $$ LANGUAGE plpgsql;
SELECT insert_records(10, 2);
SELECT * FROM testtable;
但是对于上述代码,以及我尝试过的每个变体,我都会遇到此错误(例如,在 IF 条件内先提交,然后开始,等等。
ERROR: invalid transaction termination
CONTEXT: PL/pgSQL function insert_records(integer,integer) line 9 at COMMIT
我们如何在每次第 K 次插入后提交?这个函数应该以不同的方式编写吗?谢谢。
由于 PostgreSQL 函数在周围事务块的上下文中运行,因此不允许在 PL/pgSQL 函数内使用 COMMIT。要获得可比较的结果,您应该使用 SAVEPOINT 和 ROLLBACK TO。
尝试这个更新的代码。我在此函数中使用 SAVEPOINT 来识别稍后可以回滚到的事务点。最后,它回滚到最后一个保存点,从而提交最后的一些更改,并提交所有 K 插入。通过这种方式,您可以完成每次第 K 次插入后提交的预期行为。
这是代码;
DROP TABLE IF EXISTS testtable;
CREATE TABLE IF NOT EXISTS testtable
(
identifier bigint NOT NULL,
description character varying(128),
CONSTRAINT testtable_pkey PRIMARY KEY (identifier)
);
CREATE OR REPLACE FUNCTION insert_records(N INT, K INT)
RETURNS VOID AS $$
DECLARE
i INT;
BEGIN
FOR i IN 1..N LOOP
INSERT INTO testtable (identifier, description) VALUES (i, 'some string');
IF MOD(i, K) = 0 THEN
-- Commit every K inserts
COMMIT;
-- Create a new savepoint
SAVEPOINT savepoint_insert;
END IF;
END LOOP;
-- Rollback to the last savepoint to keep the changes made after the last commit
ROLLBACK TO SAVEPOINT savepoint_insert;
-- Commit the remaining changes
COMMIT;
END $$ LANGUAGE plpgsql;
-- Call the function
SELECT insert_records(10, 2);
-- Check the results
SELECT * FROM testtable;
希望对你有帮助:)