這很重要
寫入 Unity Catalog 管理的 Iceberg 表格的交易則在 私人預覽中。 要加入此預覽,請提交 管理的 Iceberg 表格預覽報名表單。
在這個教學中,你會使用兩種交易模式來協調 Azure Databricks 上多個語句和資料表的更新:非互動模式(non-interactive (BEGIN ATOMIC),自動提交,以及互動式(interactive (BEGIN TRANSACTION),給你明確的控制權。 教學也示範如何使用交易與儲存程序及 SQL 腳本。
要求
- Environment:存取Azure Databricks工作空間。
- 運算:支援的運算類型依交易模式而異:
-
權限:
CREATE TABLE在 Unity 目錄 架構中。
建立取樣表
所有在多語句、多資料表交易中寫入的資料表必須:
- Be Unity Catalog 管理的資料表(Delta 或 Iceberg)
- 啟用目錄提交
-- 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'
);
備註
要啟用現有資料表的交易,請執行:
ALTER TABLE <table_name> SET TBLPROPERTIES ('delta.feature.catalogManaged' = 'supported');
將樣本資料插入兩個表格:
INSERT INTO sample_accounts VALUES
(1, 'Alice', 1000.00),
(2, 'Bob', 500.00);
INSERT INTO sample_transactions VALUES
(1, 1, 'deposit', 100.00);
確認設置:
SELECT * FROM sample_accounts;
SELECT * FROM sample_transactions;
輸出:
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
非互動式交易
非互動式交易則使用 BEGIN ATOMIC ... END; 語法。 所有語句都作為一個單一原子單位運行。 如果每個陳述都成功,Azure Databricks 會自動提交。 如果任何陳述失敗,Azure Databricks 會自動回滾所有變更。 關於詳細語法與使用模式,請參見 非互動式交易。
成功執行交易
以原子方式更新兩個資料表:
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;
確認 Alice 的餘額現在是 1100.00:
SELECT * FROM sample_accounts WHERE id = 1;
請確認現在有兩筆交易紀錄:
SELECT * FROM sample_transactions;
餘額更新和交易紀錄都是一起建立的。 若任一敘述失敗,則兩項變更都不會提交,Databricks 也會終止交易,且不會有副作用。
使用 SIGNAL 使交易在某個條件下失敗
你可以在SIGNAL區塊內使用BEGIN ATOMIC ... END;,當未符合使用者定義條件時導致交易失敗。 此範例插入一個餘額為負的帳戶,然後在餘額檢查失敗時,使用 SIGNAL 使交易失敗:
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 會產生錯誤,造成整個交易自動回滾。 此時回傳零列,因為插入件已被回滾:
SELECT * FROM sample_accounts WHERE id = 3;
請參見故障時自動回滾
執行一個交易,第一個陳述句有效,但第二個陳述句引用一個不存在的資料表:
BEGIN ATOMIC
-- Valid
INSERT INTO sample_accounts VALUES (4, 'David', 300.00);
-- Invalid
INSERT INTO non_existent_table VALUES (1, 2, 3);
END;
交易會因錯誤而失敗。 此處回傳 0 列,因為整個交易都被回滾:
SELECT * FROM sample_accounts WHERE id = 4;
即使第一個 INSERT 陳述有效,但因為第二個陳述失敗,它被回滾了。 這展現了交易的全有或全無保證。
互動式交易
互動式交易讓你明確控制何時提交或回滾。 使用 BEGIN TRANSACTION 啟動,然後用 COMMIT 儲存變更,或用 ROLLBACK 丟棄變更。
提交變更
啟動交易:
BEGIN TRANSACTION;
進行變更(尚未承諾):
INSERT INTO sample_accounts VALUES (5, 'Eve', 850.00);
UPDATE sample_accounts SET balance = balance + 50.00 WHERE id = 2;
承諾讓變更永久化:
COMMIT;
確認 Eve 的帳號現在可見:
SELECT * FROM sample_accounts WHERE id = 5;
請確認 Bob 的餘額現在是 550.00:
SELECT * FROM sample_accounts WHERE id = 2;
回復變更
開始新交易:
BEGIN TRANSACTION;
做出改變:
INSERT INTO sample_accounts VALUES (6, 'Frank', 600.00);
確認變更在你的工作階段中可見(該列在提交前不會被其他工作階段看到):
SELECT * FROM sample_accounts WHERE id = 6;
復原以丟棄變更:
ROLLBACK;
此時回傳零列,因為插入件已被回滾:
SELECT * FROM sample_accounts WHERE id = 6;
用於儲存程序和 SQL 腳本
你可以將交易與 儲存程序 結合,建立可重複使用的交易邏輯。 此模式對於經常執行的複雜操作非常有用。
建立啟用目錄提交的資料表
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');定義儲存程序
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;定義交易
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
如果交易的任何部分失敗,Databricks 將會自動回復所有變更。
清除
移除樣本表:
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;
其他資源
- 交易:交易支援概述。
- 交易模式:兩種模式的詳細語法與模式。
- 目錄提交:在您的資料表上啟用交易支援。
- 使用不同客戶端的交易:執行 JDBC、ODBC 及 Python 應用程式的交易。
- ATOMIC 複合語句(非互動式交易)
- 開始交易(互動式交易)
- COMMIT
- ROLLBACK