Hy vọng một câu hỏi đơn giản, nhưng một câu hỏi mà tôi chưa sẵn sàng tìm thấy một câu trả lời hợp lý. Tôi được thông báo một cách đáng tin cậy rằng các thủ tục được lưu trữ (các hàm DB do người dùng định nghĩa) trong PostgreSQL (cụ thể, phiên bản 9.0.4) vốn đã được giao dịch, vì chúng được gọi thông qua câu lệnh SELECT mà chính nó là một giao dịch. Vậy làm thế nào người ta chọn mức cô lập của thủ tục lưu sẵn? Tôi tin rằng trong các DBMS khác, khối giao dịch mong muốn sẽ được bao bọc trong khối START TRANSACTION mà mức cô lập mong muốn là một tham số tùy chọn.thiết lập mức cô lập cho các thủ tục lưu trữ postgresql
Là một làm-up cụ thể ví dụ, nói tôi muốn làm điều này:
CREATE FUNCTION add_new_row(rowtext TEXT)
RETURNS VOID AS
$$
BEGIN
INSERT INTO data_table VALUES (rowtext);
UPDATE row_counts_table SET count=count+1;
END;
$$
LANGUAGE plpgsql
SECURITY DEFINER;
Và hãy tưởng tượng tôi muốn chắc chắn chức năng này luôn được thực hiện như một giao dịch serializable (vâng, vâng, PostgreSQL isn SERIALIZABLE không thể tuần tự đúng, nhưng đó không phải là vấn đề). Tôi không muốn yêu cầu nó được gọi là
START TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT add_new_row('foo');
COMMIT;
Vậy làm cách nào để đẩy mức cách ly bắt buộc vào chức năng? Tôi tin rằng tôi không thể chỉ cần đặt mức cô lập trong báo cáo BEGIN
, như the manual says
Điều quan trọng là không để nhầm lẫn giữa việc sử dụng của BEGIN/END cho nhóm báo cáo trong PL/pgSQL với cùng tên SQL lệnh để kiểm soát giao dịch. BEGIN/END của PL/pgSQL chỉ dành cho nhóm; họ không bắt đầu hoặc kết thúc giao dịch . Chức năng và kích hoạt thủ tục luôn thực hiện trong vòng một giao dịch được thiết lập bởi một truy vấn bên ngoài - họ không thể bắt đầu hoặc cam kết giao dịch đó, vì sẽ có no context cho họ để thực hiện trong
Rõ ràng nhất. cách tiếp cận đối với tôi sẽ được sử dụng SET TRANSACTION
đâu đó trong định nghĩa hàm, ví dụ ,:
CREATE FUNCTION add_new_row(rowtext TEXT)
RETURNS VOID AS
$$
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
INSERT INTO data_table VALUES (rowtext);
UPDATE row_counts_table SET count=count+1;
END;
$$
LANGUAGE plpgsql
SECURITY DEFINER;
trong khi điều này sẽ được chấp nhận, nó không phải là rõ ràng hơn tôi có thể dựa vào điều này để làm việc. Các documentation cho SET TRANSACTION
nói
Nếu SET GIAO DỊCH được thực hiện mà không cần một START GIAO DỊCH trước hoặc BEGIN, nó sẽ xuất hiện để không có hiệu lực, kể từ giao dịch ngay lập tức sẽ kết thúc.
Những lá tôi bối rối, vì nếu tôi gọi một SELECT add_new_row('foo');
tuyên bố đơn độc Tôi mong chờ (với điều kiện tôi chưa tắt autocommit) SELECT được chạy như một giao dịch duy nhất phù hợp với mức độ cô lập phiên mặc định.
Các manual cũng nói:
Giao dịch mức cô lập không thể được thay đổi sau khi truy vấn đầu tiên hoặc tuyên bố dữ liệu sửa đổi (SELECT, INSERT, DELETE, UPDATE, FETCH, hoặc COPY) của một giao dịch đã được thực hiện .
Vậy điều gì sẽ xảy ra nếu hàm được gọi từ bên trong một giao dịch với một mức độ cô lập thấp hơn, ví dụ,:.
START TRANSACTION ISOLATION LEVEL READ COMMITTED;
UPDATE row_counts_table SET count=0;
SELECT add_new_row('foo');
COMMIT;
Đối với một câu hỏi bonus: không ngôn ngữ của chức năng thực hiện bất kỳ sự khác biệt? Liệu một trong những thiết lập mức độ cô lập khác nhau trong PL/pgSQL hơn trong SQL đơn giản?
Tôi là người hâm mộ các tiêu chuẩn và các phương pháp hay nhất được viết thành tài liệu, vì vậy mọi tham chiếu phong nha sẽ được đánh giá cao.
Điều gì đã xảy ra khi bạn cố sử dụng 'SET TRANSACTION' bên trong chức năng? –
@a_horse_with_no_name: Như tôi đã đề cập, tôi thấy 'SET TRANSACTION' là những gì tôi cần, và chức năng với nó được chấp nhận, nhưng đôi khi điều đó không có nghĩa nhiều (một số tùy chọn chỉ thỉnh thoảng nuốt), vì vậy tôi đang tìm một cách tiếp cận tài liệu hơn là một cái gì đó mà dường như chỉ hoạt động. – beldaz
Postgres hiếm khi nuốt những gì bạn bảo nó làm - và khi nào tôi mong đợi nó sẽ đưa ra cảnh báo. –