Självstudie: Samordna transaktioner mellan tabeller

Viktigt!

Transaktioner som skriver till hanterade Delta-tabeller i Unity Catalog finns i offentlig förhandsversion.

Transaktioner som skriver till hanterade Iceberg-tabeller i Unity Catalog finns i privat förhandsversion. Om du vill ansluta till den här förhandsversionen skickar du registreringsformuläret för förhandsversionen av hanterade Iceberg-tabeller.

I den här självstudien använder du båda transaktionslägena för att samordna uppdateringar i flera satser och tabeller i Azure Databricks: icke-interaktivt (BEGIN ATOMIC), som genomförs automatiskt, och interaktivt (BEGIN TRANSACTION), vilket ger dig uttrycklig kontroll. Självstudien visar också hur du använder transaktioner med lagrade procedurer och SQL-skript.

Requirements

  • Environment: Åtkomst till en Azure Databricks arbetsyta.
  • Beräkning: Beräkningstyper som stöds varierar beroende på transaktionsläge:
    • Ett klassiskt eller serverlöst SQL-lager stöder båda transaktionslägena.
    • Serverlös beräkning stöder endast icke-interaktiva transaktioner.
    • Klassiska kluster som kör Databricks Runtime 18.0 eller senare stöder endast icke-interaktiva transaktioner.
  • Behörigheter: CREATE TABLE i ett Unity Catalog-schema .

Konfigurera exempeltabeller

Alla tabeller som skrivs till vid en transaktion med flera instruktioner och flera tabeller måste:

Skapa två exempeltabeller i SQL-redigeraren eller en notebook-fil:

-- Account data
CREATE TABLE IF NOT EXISTS sample_accounts (
  id INT,
  account_name STRING,
  balance DECIMAL(10,2)
) USING DELTA
TBLPROPERTIES (
  'delta.feature.catalogManaged' = 'supported'
);

-- Transaction records
CREATE TABLE IF NOT EXISTS sample_transactions (
  id INT,
  account_id INT,
  transaction_type STRING,
  amount DECIMAL(10,2)
) USING DELTA
TBLPROPERTIES (
  'delta.feature.catalogManaged' = 'supported'
);

Note

Om du vill aktivera transaktioner i en befintlig tabell kör du:

ALTER TABLE <table_name> SET TBLPROPERTIES ('delta.feature.catalogManaged' = 'supported');

Infoga exempeldata i båda tabellerna:

INSERT INTO sample_accounts VALUES
  (1, 'Alice', 1000.00),
  (2, 'Bob', 500.00);

INSERT INTO sample_transactions VALUES
  (1, 1, 'deposit', 100.00);

Kontrollera konfigurationen:

SELECT * FROM sample_accounts;
SELECT * FROM sample_transactions;

Resultat:

sample_accounts:
id	account_name	balance
1	  Alice	        1000.00
2	  Bob	          500.00

sample_transactions:
id	account_id	transaction_type	amount
1	           1	         deposit	100.00

Icke-interaktiva transaktioner

Icke-interaktiva transaktioner använder BEGIN ATOMIC ... END; syntax. Alla instruktioner körs som en enda atomisk enhet. Om varje sats lyckas, committerar Azure Databricks automatiskt. Om någon instruktion misslyckas återställer Azure Databricks alla ändringar automatiskt. Detaljerade syntax- och användningsmönster finns i icke-interaktiva transaktioner.

Köra en lyckad transaktion

Uppdatera båda tabellerna atomiskt:

BEGIN ATOMIC
  -- Update Alice's account balance
  UPDATE sample_accounts
  SET balance = balance + 100.00
  WHERE id = 1;

  -- Record the deposit transaction
  INSERT INTO sample_transactions
  VALUES (2, 1, 'deposit', 100.00);
END;

Kontrollera att Alices saldo nu är 1100,00:

SELECT * FROM sample_accounts WHERE id = 1;

Kontrollera att det nu finns två transaktionsposter:

SELECT * FROM sample_transactions;

Både saldouppdateringen och transaktionsposten skapades tillsammans. Om någon av deklarationerna hade misslyckats skulle ingen av ändringarna ha åtagits, och Databricks skulle ha avslutat transaktionen utan sidoeffekter.

Använd SIGNAL för att misslyckas med en transaktion på ett villkor

Du kan använda SIGNAL i ett BEGIN ATOMIC ... END; block för att misslyckas med transaktionen när ett användardefinierat villkor inte uppfylls. Det här exemplet infogar ett konto med ett negativt saldo och använder SIGNAL sedan för att misslyckas med transaktionen om saldokontrollen misslyckas:

BEGIN ATOMIC
  INSERT INTO sample_accounts VALUES (3, 'Charlie', -50.00);

  IF (SELECT balance FROM sample_accounts WHERE id = 3) < 0 THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Account balance cannot be negative';
  END IF;
END;

SIGNAL Genererar ett fel som gör att hela transaktionen återställs automatiskt. Detta returnerar noll rader eftersom infogningen återställdes:

SELECT * FROM sample_accounts WHERE id = 3;

Se automatisk återställning vid fel

Kör en transaktion där den första instruktionen är giltig men den andra refererar till en tabell som inte finns:

BEGIN ATOMIC
  -- Valid
  INSERT INTO sample_accounts VALUES (4, 'David', 300.00);
  -- Invalid
  INSERT INTO non_existent_table VALUES (1, 2, 3);
END;

Transaktionen misslyckas med ett fel. Detta returnerar 0 rader eftersom hela transaktionen återställdes:

SELECT * FROM sample_accounts WHERE id = 4;

Även om den första INSERT instruktionen var giltig återställdes den eftersom den andra instruktionen misslyckades. Detta visar allt-eller-inget-garantin för transaktioner.

Interaktiva transaktioner

Interaktiva transaktioner ger dig explicit kontroll över när du ska komplettera eller rulla tillbaka. Använd BEGIN TRANSACTION för att starta och sedan COMMIT för att spara ändringar eller ROLLBACK för att ta bort dem.

Utför ändringar

Starta en transaktion:

BEGIN TRANSACTION;

Gör ändringar (har ännu inte bekräftats):

INSERT INTO sample_accounts VALUES (5, 'Eve', 850.00);
UPDATE sample_accounts SET balance = balance + 50.00 WHERE id = 2;

Bekräfta för att göra ändringar permanenta:

COMMIT;

Kontrollera att Eves konto nu är synligt:

SELECT * FROM sample_accounts WHERE id = 5;

Kontrollera att Bobs saldo nu 550.00är :

SELECT * FROM sample_accounts WHERE id = 2;

Återställa ändringar

Starta en ny transaktion:

BEGIN TRANSACTION;

Gör en ändring:

INSERT INTO sample_accounts VALUES (6, 'Frank', 600.00);

Kontrollera att ändringen är synlig i din session (raden är inte synlig för andra sessioner förrän den har committerats):

SELECT * FROM sample_accounts WHERE id = 6;

Återställ för att ignorera ändringen:

ROLLBACK;

Detta returnerar noll rader eftersom infogningen återställdes:

SELECT * FROM sample_accounts WHERE id = 6;

Använda med lagrade procedurer och SQL-skript

Du kan kombinera transaktioner med lagrade procedurer för att skapa återanvändbar transaktionslogik. Det här mönstret är användbart för komplexa åtgärder som du kör ofta.

  1. Skapa tabellerna med katalogincheckningar aktiverade

    CREATE SCHEMA IF NOT EXISTS main.retail;
    
    CREATE TABLE IF NOT EXISTS main.retail.orders (
      order_id STRING,
      customer_id STRING,
      amount DECIMAL(18,2)
    ) TBLPROPERTIES ('delta.feature.catalogManaged' = 'supported');
    
    CREATE TABLE IF NOT EXISTS main.retail.orders_staging (
      order_id STRING,
      customer_id STRING,
      amount DECIMAL(18,2),
      batch_id STRING
    ) TBLPROPERTIES ('delta.feature.catalogManaged' = 'supported');
    
    CREATE TABLE IF NOT EXISTS main.retail.total_sales (
      customer_id STRING,
      total_amount DECIMAL(18,2)
    ) TBLPROPERTIES ('delta.feature.catalogManaged' = 'supported');
    
  2. Definiera den lagrade proceduren

    CREATE OR REPLACE PROCEDURE main.retail.apply_order(
        IN  p_order_id      STRING,
        IN  p_customer_id   STRING,
        IN  p_order_amount  DECIMAL(18,2)
    )
    LANGUAGE SQL
    SQL SECURITY INVOKER
    MODIFIES SQL DATA
    AS
    BEGIN
        -- Insert the order
        INSERT INTO main.retail.orders (order_id, customer_id, amount)
        VALUES (p_order_id, p_customer_id, p_order_amount);
    
        -- Update total sales per customer
        MERGE INTO main.retail.total_sales AS t
        USING (
            SELECT
              p_customer_id  AS customer_id,
              p_order_amount AS order_amount
        ) s
          ON t.customer_id = s.customer_id
        WHEN MATCHED THEN
          UPDATE SET t.total_amount = t.total_amount + s.order_amount
        WHEN NOT MATCHED THEN
          INSERT (customer_id, total_amount)
          VALUES (s.customer_id, s.order_amount);
    END;
    
    
  3. Definiera transaktionen

    BEGIN ATOMIC
        -- Staging batch id for this transaction
        DECLARE new_order_id STRING DEFAULT uuid();
        DECLARE v_batch_id STRING DEFAULT uuid();
    
        -- 1) Stage incoming customer and order rows
        INSERT INTO main.retail.orders_staging (order_id, customer_id, amount, batch_id)
        VALUES (new_order_id, 'CUST_123', 249.99, v_batch_id);
    
        -- 2) Drive final writes from staging to production via stored procedure
        FOR o AS
          SELECT
            order_id,
            customer_id,
            amount
          FROM main.retail.orders_staging
          WHERE batch_id = v_batch_id
        DO
            CALL main.retail.apply_order(
              o.order_id,
              o.customer_id,
              o.amount
            );
        END FOR;
    
        -- 3) Clean up processed staging rows
        DELETE FROM main.retail.orders_staging
        WHERE batch_id = v_batch_id;
    END; -- 4) Commit the transaction
    
    

Om någon del av transaktionen misslyckas återställer Databricks alla ändringar automatiskt.

Rensa

Ta bort exempeltabellerna:

DROP TABLE IF EXISTS sample_accounts;
DROP TABLE IF EXISTS sample_transactions;

DROP TABLE IF EXISTS main.retail.orders;
DROP TABLE IF EXISTS main.retail.orders_staging;
DROP TABLE IF EXISTS main.retail.total_sales;

Ytterligare resurser