Pular para o conteúdo principal

Tutorial: Coordenar transações entre tabelas

info

Visualização

Transações que gravam no Unity Catalog gerenciam tabelas Delta e estão em Pré-visualização Pública.

Transações que gravam em tabelas Iceberg gerenciadas Unity Catalog estão em Pré-visualização Privada. Para join desta pré-visualização, envie o formulário de inscrição para a pré-visualização das mesas Iceberg.

Este tutorial demonstra como usar transações para coordenar atualizações em várias instruções e tabelas. Você aprenderá os dois modos de transação: transações não interativas, que commit automaticamente, e transações interativas, que lhe dão controle explícito. O tutorial também demonstra o uso de transações com procedimentos armazenados e scripts SQL para criar cargas de trabalho de armazenamento de dados de missão crítica no Databricks.

Requisitos

  • Ambiente : Acesso a um workspace Databricks .

  • Computação : Os tipos compute suportados variam de acordo com o modo de transação:

    • Um SQL warehouse clássico ou serverless suporta ambos os modos de transação.
    • computesem servidor suporta apenas transações não interativas.
    • clusters clássicos que executam Databricks Runtime 18.0 ou superior suportam apenas transações não interativas.
  • Privilégios : CREATE TABLE em um esquema Unity Catalog .

Configure tabelas de exemplo

Todas as tabelas que são gravadas em uma transação com várias instruções e várias tabelas devem:

Crie duas tabelas de exemplo no EditorSQL ou em um Notebook:

SQL
-- Create a table for 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'
);

-- Create a table for 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'
);

-- To upgrade an existing table, use:
-- ALTER TABLE <table_name> SET TBLPROPERTIES ('delta.feature.catalogManaged' = 'supported');

-- Insert sample data
INSERT INTO sample_accounts VALUES
(1, 'Alice', 1000.00),
(2, 'Bob', 500.00);

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

Verifique a configuração:

SQL
SELECT * FROM sample_accounts;
SELECT * FROM sample_transactions;

Saída:

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

Transações não interativas

Transações não interativas usam a sintaxe BEGIN ATOMIC ... END; . A execução de todas as instruções ocorre como uma única unidade atômica. Se todas as instruções forem bem-sucedidas, o Databricks realiza o commit automaticamente. Se alguma instrução falhar, o Databricks reverte todas as alterações automaticamente. Para obter detalhes sobre a sintaxe e os padrões de uso, consulte transações não interativas.

execução de uma transação bem-sucedida

Atualize ambas as tabelas atomicamente:

SQL
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;

Verifique se ambas as operações foram bem-sucedidas:

SQL
-- Alice's balance should now be 1100.00
SELECT * FROM sample_accounts WHERE id = 1;

-- Should show two transaction records
SELECT * FROM sample_transactions;

A atualização do saldo e o registro da transação foram criados simultaneamente. Se alguma das instruções tivesse falhado, nenhuma das alterações teria sido confirmada e o Databricks teria encerrado a transação sem efeitos colaterais.

Use SIGNAL para interromper uma transação sob uma condição.

Você pode usar SIGNAL dentro de um bloco BEGIN ATOMIC ... END; para falhar a transação quando uma condição definida pelo usuário não for atendida. Isso é útil para validação de dados antes do commit:

SQL
BEGIN ATOMIC
-- Insert new account
INSERT INTO sample_accounts VALUES (3, 'Charlie', -50.00);

-- Fail the transaction if balance is negative
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;

O SIGNAL gera um erro, o que faz com que toda a transação seja revertida automaticamente. Verifique se o inserto foi revertido:

SQL
-- Should return 0 rows (the transaction was rolled back by SIGNAL)
SELECT * FROM sample_accounts WHERE id = 3;

Consulte a seção sobre reversão automática em caso de falha.

executar uma transação com uma instrução inválida:

SQL
BEGIN ATOMIC
-- This statement is valid
INSERT INTO sample_accounts VALUES (4, 'David', 300.00);

-- This statement will fail (table does not exist)
INSERT INTO non_existent_table VALUES (1, 2, 3);
END;

A transação falhou com um erro. Verifique se a primeira instrução foi revertida:

SQL
-- Should return 0 rows because the transaction was rolled back
SELECT * FROM sample_accounts WHERE id = 4;

Embora a primeira instrução INSERT fosse válida, ela foi revertida porque a segunda instrução falhou. Isso demonstra a garantia de "tudo ou nada" das transações.

Transações interativas

Transações interativas oferecem controle explícito sobre quando commit ou reverter a transação. Use BEGIN TRANSACTION para iniciar e, em seguida, confirme para salvar as alterações ou ROLLBACK para descartá-las.

confirmar alterações

Iniciar uma transação:

SQL
BEGIN TRANSACTION;

Fazer alterações (ainda não confirmadas):

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

Comprometa-se a tornar as mudanças permanentes:

SQL
COMMIT;

Verifique as alterações:

SQL
-- Eve's account should now be visible
SELECT * FROM sample_accounts WHERE id = 5;

-- Bob's balance should be 550.00 (500 + 50)
SELECT * FROM sample_accounts WHERE id = 2;

Reverter alterações

Iniciar uma nova transação:

SQL
BEGIN TRANSACTION;

Faça uma mudança:

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

Verifique se a alteração está visível na sua sessão:

SQL
-- Should show Frank's account (visible in your session only)
SELECT * FROM sample_accounts WHERE id = 6;

Reverter para descartar a alteração:

SQL
ROLLBACK;

Verifique se a alteração foi descartada:

SQL
-- Should return 0 rows (the insert was rolled back)
SELECT * FROM sample_accounts WHERE id = 6;

Utilizar com procedimentos armazenados e scripts SQL.

Você pode combinar transações com procedimentos armazenados para criar uma lógica de transação reutilizável. Este padrão é útil para operações complexas que você executa com frequência.

  1. Crie duas tabelas com o comando `catalog-gerenciar commit` ativado.

    SQL

    CREATE TABLE orders (order_id STRING, item_sku STRING, quantity_ordered INT)
    TBLPROPERTIES ('delta.feature.catalogManaged' = 'supported');

    CREATE TABLE inventory (item_sku STRING, quantity_in_stock INT)
    TBLPROPERTIES ('delta.feature.catalogManaged' = 'supported');

  2. Defina o procedimento armazenado

    SQL
    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. Defina a transação

    SQL
    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

Se alguma parte da transação falhar, o Databricks reverte todas as alterações automaticamente.

Limpar

Remova as tabelas de exemplo:

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


DROP TABLE IF EXISTS orders;
DROP TABLE IF EXISTS inventory;

Próximos passos

Referência SQL relacionada