Compartilhar via


Tutorial: Coordenar transações entre tabelas

Importante

As transações que gravam em tabelas Delta gerenciadas pelo Catálogo Unity estão em Visualização Pública.

As transações que gravam em tabelas Iceberg gerenciadas pelo Unity Catalog estão em Versão Prévia Privada. Para ingressar nesta prévia, envie o formulário de inscrição para prévia das tabelas Iceberg gerenciadas.

Este tutorial demonstra como usar transações para coordenar atualizações em múltiplas instruções e tabelas. Você aprende os dois modos de transação: transações não interativas, que são confirmadas 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 armazenagem críticas no Azure Databricks.

Requisitos

  • Ambiente: Acesso a um workspace do Azure Databricks.
  • Computação: os tipos de computação com suporte variam de acordo com o modo de transação:
  • Privilégios: CREATE TABLE em um Catálogo Unity schema.

Configurar tabelas de exemplo

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

Crie duas tabelas de exemplo no Editor do SQL ou em um notebook:

-- 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:

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 BEGIN ATOMIC ... END; sintaxe. Todas as instruções são executadas como uma única unidade atômica. Se cada instrução for bem-sucedida, o Azure Databricks confirma automaticamente. Se alguma instrução falhar, o Azure Databricks reverterá todas as alterações automaticamente. Para obter padrões detalhados de sintaxe e uso, consulte transações não interativas.

Executar uma transação bem-sucedida

Atualize ambas as tabelas atomicamente:

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:

-- 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 de saldo e o registro de transação foram criados juntos. Se qualquer uma das instruções tivesse falhado, nenhuma mudança teria sido confirmada e Databricks teria encerrado a transação sem efeitos colaterais.

Usar SIGNAL para interromper uma transação sob uma condição

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

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;

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

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

Veja a reversão automática em caso de falha

Executar uma transação com uma declaração inválida:

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 falha com um erro. Verifique se a primeira declaração foi revertida.

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

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

Transações interativas

Transações interativas fornecem controle explícito sobre quando confirmar ou reverter. Use BEGIN TRANSACTION para iniciar e, em seguida, COMMIT para salvar alterações ou ROLLBACK para descartá-las.

Confirmar alterações

Inicie uma transação:

BEGIN TRANSACTION;

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

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

Confirme-se para tornar as alterações permanentes:

COMMIT;

Verifique as alterações:

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

Inicie uma nova transação:

BEGIN TRANSACTION;

Faça uma alteração:

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

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

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

Reverta para descartar a alteração:

ROLLBACK;

Verifique se a alteração foi descartada:

-- 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 lógica de transação reutilizável. Esse padrão é útil para operações complexas executadas com frequência.

  1. Criar duas tabelas com confirmações gerenciadas pelo catálogo habilitadas

    
    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. Definir o procedimento armazenado

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

    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 qualquer parte da transação falhar, o Databricks reverterá todas as alterações automaticamente.

Limpar

Remova as tabelas de exemplo:

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


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

Próximas Etapas