PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Cam kết Postgres có thể tồn tại trong thủ tục có khối ngoại lệ không?

Ngữ nghĩa của xử lý lỗi ra lệnh rằng:

Điều này được triển khai bằng cách sử dụng các giao dịch con, về cơ bản giống với các điểm lưu . Nói cách khác, khi bạn chạy mã PL / pgSQL sau:

BEGIN
  PERFORM foo();
EXCEPTION WHEN others THEN
  PERFORM handle_error();
END

... những gì thực sự đang xảy ra là một cái gì đó như thế này:

BEGIN
  SAVEPOINT a;
  PERFORM foo();
  RELEASE SAVEPOINT a;
EXCEPTION WHEN others THEN
  ROLLBACK TO SAVEPOINT a;
  PERFORM handle_error();
END

COMMIT trong khối sẽ phá vỡ điều này hoàn toàn; các thay đổi của bạn sẽ được thực hiện vĩnh viễn, điểm lưu sẽ bị loại bỏ và trình xử lý ngoại lệ sẽ không có cách nào để quay trở lại. Do đó, các cam kết không được phép trong ngữ cảnh này và cố gắng thực thi COMMIT sẽ dẫn đến lỗi "không thể cam kết trong khi giao dịch con đang hoạt động".

Đó là lý do tại sao bạn thấy thủ tục của mình chuyển đến trình xử lý ngoại lệ thay vì chạy raise notice 'B' :khi nó đạt đến commit , nó tạo ra một lỗi và trình xử lý sẽ bắt được nó.

Tuy nhiên, điều này khá dễ hiểu. BEGIN ... END các khối có thể được lồng vào nhau và chỉ các khối có EXCEPTION các mệnh đề liên quan đến việc thiết lập các điểm lưu, vì vậy bạn có thể chỉ cần bọc các lệnh trước và sau cam kết trong các trình xử lý ngoại lệ của riêng chúng:

create or replace procedure x_transaction_try() language plpgsql
as $$
declare
  my_ex_state text;
  my_ex_message text;
  my_ex_detail text;
  my_ex_hint text;
  my_ex_ctx text;
begin
  begin
    raise notice 'A';
  exception when others then
    raise notice 'C';
    GET STACKED DIAGNOSTICS
      my_ex_state   = RETURNED_SQLSTATE,
      my_ex_message = MESSAGE_TEXT,
      my_ex_detail  = PG_EXCEPTION_DETAIL,
      my_ex_hint    = PG_EXCEPTION_HINT,
      my_ex_ctx     = PG_EXCEPTION_CONTEXT
    ;
    raise notice '% % % % %', my_ex_state, my_ex_message, my_ex_detail, my_ex_hint, my_ex_ctx;
  end;

  commit;

  begin
    raise notice 'B';
  exception when others then
    raise notice 'C';
    GET STACKED DIAGNOSTICS
      my_ex_state   = RETURNED_SQLSTATE,
      my_ex_message = MESSAGE_TEXT,
      my_ex_detail  = PG_EXCEPTION_DETAIL,
      my_ex_hint    = PG_EXCEPTION_HINT,
      my_ex_ctx     = PG_EXCEPTION_CONTEXT
    ;
    raise notice '% % % % %', my_ex_state, my_ex_message, my_ex_detail, my_ex_hint, my_ex_ctx;
  end;      
end;
$$;

Thật không may, nó dẫn đến nhiều sự trùng lặp trong các trình xử lý lỗi, nhưng tôi không thể nghĩ ra cách hay để tránh nó.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Rake db:thả không xóa các bảng cũ của tôi

  2. Các thông số có giá trị của bảng Postgresql JDBC

  3. Sự cố khi kết nối Pentaho Kettle / Spoon với Heroku PostgreSQL bằng SSL

  4. Triển khai ứng dụng Django mà không bị gián đoạn dịch vụ / không có thời gian ngừng hoạt động

  5. Triển khai Django cho Heroku (Lỗi Psycopg2)