簡體   English   中英

觸發錯誤時回滾事務

[英]Rollback Transaction on Trigger ERROR

我正在嘗試檢查將要插入系統的房間在該日期是否已經租用。 我已經考慮過計算與房間號和日期匹配的行,然后回滾事務。 但是我收到以下錯誤,即使我已經更改了代碼以引發用戶定義的異常:

 ERROR: cannot begin/end transactions in PL/pgSQL HINT: Use a BEGIN block with an EXCEPTION clause instead. CONTEXT: PL/pgSQL function "checkRoom"() line 17 at SQL statement
CREATE OR REPLACE FUNCTION "checkRoom"() RETURNS TRIGGER AS
$BODY$
DECLARE 
    counter integer;
  BEGIN
    SELECT COUNT("num_sesion")
    FROM "Sesion"
    INTO counter
    WHERE "Room_Name"=NEW."Room_Name" AND "Date"=NEW."Date";

    IF (counter> 0) THEN -- Probably counter>1 as it's triggered after the transaction..
        raise notice 'THERE'S A ROOM ALREADY!!';
        raise exception 'The room is rented at that date';
    END IF;
    RETURN new;
EXCEPTION
    WHEN raise_exception THEN
        ROLLBACK TRANSACTION;
        RETURN new;
END;$BODY$
LANGUAGE plpgsql VOLATILE NOT LEAKPROOF;

然后我創建觸發器:

CREATE TRIGGER "roomOcupied" AFTER INSERT OR UPDATE OF "Room_Name", "Date"
ON "Sesion" FOR EACH ROW
EXECUTE PROCEDURE "checkRoom"();

從我上次使用 SQL 到現在已經 2 年了,plsql 和 plpgsql 之間的變化讓我很抓狂。

您的觸發器功能有幾個問題:

  • 使用IF EXISTS (...) THEN而不是計算所有出現的次數。 更快,更簡單。 看:

  • INSERT OR UPDATE AFTER的觸發器函數可以只返回NULL RETURN NEW僅與稱為BEFORE觸發器相關。 手冊

    操作后觸發的行級觸發器的返回值將被忽略,因此它們可以返回NULL

  • 不平衡的單引號。

  • 正如@Pavel 解釋的那樣,您無法從 plpgsql 函數中控制事務。 任何未處理的異常都會強制您的整個事務自動回滾。 因此,只需刪除EXCEPTION塊。

你的假設觸發器重寫:

CREATE OR REPLACE FUNCTION check_room()
  RETURNS TRIGGER AS
$func$
BEGIN
   IF EXISTS (
         SELECT FROM "Sesion"    -- are you sure it's not "Session"?
         WHERE  "Room_Name" = NEW."Room_Name"
         AND    "Date" = NEW."Date") THEN
     RAISE EXCEPTION 'The room is rented at that date';
   END IF;
   RETURN NULL;
END
$func$  LANGUAGE plpgsql;

BEFORE觸發器更有意義。

但是UNIQUE INDEX ON ("Room_Name", "Date")會做同樣的事情,而且效率更高。 然后,任何違反的行都會引發重復鍵異常並回滾事務(除非被捕獲和處理)。 在現代 Postgres 中,您可以使用INSERT ... ON CONFLICT ...跳過或轉移此類INSERT嘗試。 看:

高級用法:

PostgreSQL 處理錯誤的方式與其他數據庫明顯不同。 任何未處理的錯誤都會提交給用戶。 在 PL/pgSQL 中,您可以捕獲任何異常,也可以引發任何異常,但您無法顯式控制事務。 任何 PostgreSQL 語句都在事務內執行(函數也是如此)。 當任何未處理的異常到達頂部時,最外層的事務會自動中斷。

你能做什么:

  • 引發異常(通常在觸發器中)

BEGIN
  IF CURRENT_USER <> 'Admin' THEN
    RAISE EXCEPTION 'missing admin rights';
  END IF;
  RETURN NEW;
END;
  • 捕獲異常
BEGIN
  BEGIN -- start of protected section
    -- do some, what can be stopped by exception
  EXCEPTION WHEN divide_by_zero THEN
    -- exception handler;
    RAISE WARNING 'I was here';
    -- should ignore
  EXCEPTION WHEN others THEN
    -- any unexpected exception
    RAISE WARNING 'some unexpected issue';
    RAISE; -- forward exception'
  END;

沒有其他可能性 - 所以在 PL/pgSQL 中編寫應用程序非常簡單,但與 PL/SQL 或 TSQL 不同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM