Modes de transaction
Aperçu
Les transactions qui écrivent dans les tables Iceberg gérées par Unity Catalog sont en préversion privée. Pour rejoindre cette préversion, soumettez le formulaire d'inscription à la préversion des tables Iceberg gérées.
Les transactions sur Databricks prennent en charge deux modes :
- Non interactif (
BEGIN ATOMIC) : effectue des commits ou des restaurations automatiques. Idéal pour les Jobs planifiés et les séquences d'instructions fixes. - **Interactif**
BEGIN TRANSACTION() : Vous donne un contrôle manuel sur les opérations de commit et d'annulation. Idéal pour la validation, le debugging et les clients JDBC.
Pour connaître les exigences et obtenir un aperçu des transactions, consultez Transactions. Pour une mise en pratique des deux modes, consultez Didacticiel : Coordonner les transactions entre les tables.
Toutes les tables écrites dans une transaction multi-déclaration, multi-table doivent :
- Soyez des tables gérées par Unity Catalog (Delta ou Iceberg)
- Activer les commits du catalogue
Transactions non interactives
Les transactions non interactives utilisent le scripting SQL avec le mot-clé ATOMIC. Le bloc d'instruction composée ATOMIC exécute toutes les instructions comme une seule unité atomique. Tous réussissent ou tous échouent ensemble.
Compute pris en charge : Tout SQL Warehouse, compute Serverless ou cluster exécutant Databricks Runtime 18.0 et versions ultérieures.
Syntaxe prise en charge : Prend en charge les blocs SQL, Scala spark.sql et PySpark spark.sql.
Vous pouvez utiliser des transactions non interactives dans le forEachBatch de Structured Streaming en appelant spark.sql("BEGIN ATOMIC ... END;"). Toutefois, les points de contrôle Structured Streaming n'avancent pas de manière transactionnelle.
Syntaxe
BEGIN ATOMIC
statement1;
statement2;
statement3;
END;
Databricks commit automatiquement toutes les modifications si toutes les instructions réussissent. Si une instruction échoue, Databricks annule automatiquement toutes les modifications.
Utiliser dans l’éditeur SQL
Exécutez les transactions non interactives directement dans l'éditeur SQL. Sélectionnez l'intégralité du bloc d'instructions composées ATOMIC et exécutez-le en tant qu'instruction unique :
BEGIN ATOMIC
DELETE FROM staging_sales WHERE load_date < current_date() - INTERVAL 7 DAYS;
INSERT INTO staging_sales
SELECT * FROM raw_sales WHERE load_date = current_date();
MERGE INTO sales AS target
USING staging_sales AS source
ON target.sale_id = source.sale_id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *;
END;
Utiliser dans les Notebooks
Exécutez des transactions non interactives dans des Notebooks à l'aide de cellules SQL ou d'APIs programmatiques.
- SQL
- Python
- Scala
BEGIN ATOMIC
UPDATE inventory SET quantity = quantity - 10 WHERE product_id = 2001;
UPDATE inventory SET quantity = quantity + 10 WHERE product_id = 2002;
INSERT INTO inventory_moves (from_product, to_product, quantity, move_date)
VALUES (2001, 2002, 10, current_date());
END;
spark.sql("""
BEGIN ATOMIC
UPDATE inventory SET quantity = quantity - 10 WHERE product_id = 2001;
UPDATE inventory SET quantity = quantity + 10 WHERE product_id = 2002;
INSERT INTO inventory_moves (from_product, to_product, quantity, move_date)
VALUES (2001, 2002, 10, current_date());
END;
""")
spark.sql("""
BEGIN ATOMIC
UPDATE inventory SET quantity = quantity - 10 WHERE product_id = 2001;
UPDATE inventory SET quantity = quantity + 10 WHERE product_id = 2002;
INSERT INTO inventory_moves (from_product, to_product, quantity, move_date)
VALUES (2001, 2002, 10, current_date());
END;
""")
Utiliser dans les Jobs planifiés
Les transactions non interactives fonctionnent bien dans les jobs planifiés, car elles gèrent automatiquement le commit et le rollback :
BEGIN ATOMIC
-- Clear previous staging data
DELETE FROM staging_daily_sales WHERE load_date = current_date();
-- Load new data
INSERT INTO staging_daily_sales
SELECT sale_id, customer_id, amount, sale_date, current_date() as load_date
FROM raw_sales
WHERE sale_date = current_date() - INTERVAL 1 DAY;
-- Validate row count (fails transaction if no data)
IF (SELECT COUNT(*) FROM staging_daily_sales WHERE load_date = current_date()) = 0 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'No sales data loaded for yesterday';
END IF;
-- Merge into production
MERGE INTO daily_sales AS target
USING staging_daily_sales AS source
ON target.sale_id = source.sale_id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *;
END;
Si une instruction échoue, y compris l'assertion, l'intégralité de la transaction est annulée automatiquement.
Utiliser avec JDBC
Les clients externes peuvent exécuter des transactions non interactives.
- JDBC
String sql = """
BEGIN ATOMIC
INSERT INTO orders (order_id, total) VALUES (1001, 500.00);
UPDATE customers SET last_order = CURRENT_DATE() WHERE customer_id = 5001;
END;
""";
Statement stmt = conn.createStatement();
stmt.execute(sql);
Utiliser avec l'API Statement Execution
Exécutez des transactions non interactives à l’aide de l’ API Statement Execution:
import requests
sql = """
BEGIN ATOMIC
INSERT INTO sales (sale_id, amount) VALUES (3001, 750.00);
UPDATE daily_totals SET total = total + 750.00 WHERE sale_date = CURRENT_DATE();
END;
"""
response = requests.post(
f"{workspace_url}/api/2.0/sql/statements",
headers={"Authorization": f"Bearer {token}"},
json={
"warehouse_id": warehouse_id,
"statement": sql,
"wait_timeout": "30s"
}
)
Modèles ETL
Les modèles suivants illustrent les workflows ETL courants utilisant des transactions non interactives.
Modèle de préparation et de validation
Ce modèle charge des données dans une zone de transit, valide la qualité des données et Merge les enregistrements validés dans des tables de production :
BEGIN ATOMIC
-- Load into staging
INSERT INTO staging_customers
SELECT * FROM external_source
WHERE ingest_date = current_date();
-- Validate data quality
IF (SELECT COUNT(*) FROM staging_customers WHERE email NOT LIKE '%@%') > 0 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Invalid email addresses found';
END IF;
-- Merge validated data
MERGE INTO customers AS target
USING staging_customers AS source
ON target.customer_id = source.customer_id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *;
-- Update metadata
UPDATE etl_metadata
SET last_load_date = current_date(),
rows_processed = (SELECT COUNT(*) FROM staging_customers)
WHERE table_name = 'customers';
END;
Modèle de tables de dimension et de faits
Ce modèle met à jour les tables de dimension avant de charger les tables de faits pour maintenir l'intégrité référentielle :
BEGIN ATOMIC
-- Update dimension tables first
MERGE INTO dim_products AS target
USING staging_products AS source
ON target.product_id = source.product_id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *;
MERGE INTO dim_customers AS target
USING staging_customers AS source
ON target.customer_id = source.customer_id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *;
-- Then load fact table with foreign key references
INSERT INTO fact_sales
SELECT s.sale_id, p.product_key, c.customer_key, s.sale_amount, s.sale_date
FROM staging_sales s
JOIN dim_products p ON s.product_id = p.product_id
JOIN dim_customers c ON s.customer_id = c.customer_id;
END;
Gestion des erreurs
Lorsqu'une instruction échoue dans un bloc BEGIN ATOMIC ... END;, Databricks annule toutes les modifications et renvoie un message d'erreur.
Conseils de debugging :
- Examinez le message d'erreur pour identifier quelle instruction a échoué.
- Testez les déclarations individuellement en dehors du bloc de transaction.
- Ajoutez des contrôles de validation à l’aide de
SIGNALpour échouer avec des messages d’erreur personnalisés - Interrogez l'historique des transactions pour un contexte supplémentaire.
Transactions interactives
Les transactions interactives vous donnent un contrôle explicite sur les limites des transactions. Vous lancez manuellement une transaction, exécutez des instructions et commit ou annulez explicitement.
Compute pris en charge : SQL Warehouse uniquement.
Syntaxe prise en charge : SQL uniquement.
Syntaxe
Pour commit :
BEGIN TRANSACTION;
statement1;
statement2;
COMMIT;
Pour annuler :
BEGIN TRANSACTION;
statement1;
statement2;
ROLLBACK;
Validez avant de commit
Utilisez des transactions interactives pour valider les résultats avant de commit :
BEGIN TRANSACTION;
-- Load staging data
INSERT INTO staging_customers
SELECT * FROM external_customers
WHERE load_date = current_date();
-- Validate and commit or rollback
BEGIN
DECLARE duplicate_count INT;
SET duplicate_count = (
SELECT COUNT(*) FROM (
SELECT customer_id, COUNT(*) as cnt
FROM staging_customers
WHERE load_date = current_date()
GROUP BY customer_id
HAVING COUNT(*) > 1
)
);
IF duplicate_count > 0 THEN
ROLLBACK;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Duplicate customers found in staging data';
ELSE
MERGE INTO customers AS target
USING staging_customers AS source
ON target.customer_id = source.customer_id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *;
COMMIT;
END IF;
END;
Restauration explicite
Annulez une transaction lorsque la validation échoue ou que la logique métier nécessite de rejeter les modifications :
BEGIN TRANSACTION;
UPDATE inventory
SET quantity = quantity - 50
WHERE product_id = 2001;
-- Check if quantity would go negative
BEGIN
DECLARE new_quantity INT;
SET new_quantity = (SELECT quantity FROM inventory WHERE product_id = 2001);
IF new_quantity < 0 THEN
ROLLBACK;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Insufficient inventory for product 2001';
ELSE
COMMIT;
END IF;
END;
Utiliser avec JDBC
Le Driver JDBC prend en charge l'exécution d'instructions DML à l'aide de executeUpdate() au sein de transactions. Pour une liste d'instructions DML prises en charge, consultez Opérations prises en charge.
Les clients JDBC utilisent des transactions interactives en désactivant le mode auto-commit :
Connection conn = DriverManager.getConnection(jdbcUrl, properties);
try {
conn.setAutoCommit(false); // Start transaction mode
Statement stmt = conn.createStatement();
stmt.executeUpdate("INSERT INTO accounts (account_id, balance) VALUES (1001, 5000)");
stmt.executeUpdate("UPDATE accounts SET balance = balance - 100 WHERE account_id = 1001");
conn.commit(); // Commit the transaction
} catch (SQLException e) {
conn.rollback(); // Roll back on error
throw e;
} finally {
conn.close();
}
Opérations JDBC non prises en charge
Les opérations JDBC suivantes ne sont pas prises en charge dans les transactions interactives :
Catégorie | Non pris en charge |
|---|---|
Basculement de catalogue ou de schéma |
|
Modifications de la configuration de session |
|
Toutes les DatabaseMetaData (tous les protocoles) | Toutes les méthodes |
Métadonnées de PreparedStatement. |
|
Procédures stockées |
|
Utiliser avec ODBC
Le driver ODBC prend en charge l’exécution des instructions DML à l’aide de SQLExecute() et SQLExecDirect() dans les transactions. Pour obtenir la liste des instructions DML prises en charge, consultez Opérations prises en charge.
Les clients ODBC peuvent utiliser des transactions interactives avec le Driver ODBC Databricks à l'aide des fonctions standard de gestion des transactions ODBC.
Vous devez désactiver AutoCommit pour utiliser les transactions. Pour désactiver AutoCommit lors de l'exécution, définissez UseNativeQuery sur 1. Voir la prise en charge des requêtes ANSI SQL-92 dans ODBC.
Opérations ODBC non prises en charge
Les opérations ODBC suivantes ne sont pas prises en charge dans les transactions interactives :
Catégorie | Non pris en charge |
|---|---|
Toutes les fonctions du catalogue |
|
Définition des attributs de connexion | Changement de catalogue, modifications du niveau d'isolation et modifications du mode d'accès à l'aide de |
Traduction SQL |
|
Utiliser avec le connecteur Databricks SQL pour Python
Le connecteur Databricks SQL pour Python prend en charge l’exécution d’instructions DML à l’aide de cursor.execute() au sein des transactions. Pour une liste d'instructions DML prises en charge, consultez Opérations prises en charge.
Les applications Python peuvent utiliser des transactions interactives avec le connecteur Databricks SQL pour Python en définissant autocommit=False:
from databricks import sql
with sql.connect(
server_hostname="dbc-a1b2345c-d6e7.cloud.databricks.com",
http_path="sql/1.0/warehouses/abc123def456",
access_token="your-access-token",
autocommit=False
) as connection:
with connection.cursor() as cursor:
cursor.execute("INSERT INTO accounts (account_id, balance) VALUES (1001, 5000)")
cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE account_id = 1001")
connection.commit()
Opérations du connecteur Python non prises en charge
Les opérations suivantes du connecteur Python ne sont pas prises en charge dans les transactions interactives :
Catégorie | Non pris en charge |
|---|---|
Toutes les métadonnées |
|
Limitations du Driver pour les transactions interactives
Les limitations suivantes s'appliquent à tous les drivers lors de l'utilisation de transactions interactives.
Les opérations de Metadata ne sont pas prises en charge dans les transactions interactives. Les Opérations suivantes peuvent échouer au sein d'une transaction indépendamment du Driver ou du protocole :
Driver/Protocole | Type | Méthodes |
|---|---|---|
JDBC |
|
|
ODBC | Fonctions du catalogue |
|
Connecteur Python | Méthodes de métadonnées |
|
SQL | Commandes de métadonnées |
|
Databricks vous recommande d'exécuter ces opérations de métadonnées en dehors des transactions.
L’exécution de transactions sur plusieurs threads sur un seul objet de connexion Driver entraîne un comportement indéfini. Exécutez une seule transaction à la fois sur chaque objet de connexion.
Comportement d'isolation
Les modifications non validées dans une transaction interactive ne sont visibles que par votre session. Les modifications ne sont visibles par les autres sessions qu'une fois que vous exécutez COMMIT;.
Les transactions interactives utilisent une détection des conflits plus conservatrice que les transactions non interactives et peuvent entrer en conflit au niveau de la table (sauf pour les ajouts inconditionnels). Pour la détection des conflits au niveau des lignes, utilisez des transactions non interactives (BEGIN ATOMIC ... END;).
- Pour vérifier l'isolation, créez la table d'échantillons si elle n'existe pas :
CREATE TABLE IF NOT EXISTS sample_accounts (
id INT,
account_name STRING,
balance DECIMAL(10,2)
) USING DELTA
TBLPROPERTIES ('delta.feature.catalogManaged' = 'supported');
-
Dans la même session, start une transaction et apportez une modification :
SQLBEGIN TRANSACTION;
INSERT INTO sample_accounts VALUES (10, 'Test', 100.00); -
Dans un onglet d'éditeur SQL ou une session de Notebook séparé (pas une nouvelle cellule dans le même Notebook), interrogez la table :
SQL-- Run this in the SECOND session
SELECT * FROM sample_accounts WHERE id = 10;Ceci renvoie 0 ligne, car la modification non validée n'est pas visible en dehors de votre première session.
-
Retournez à votre première session et commit :
SQLCOMMIT; -
Query de la deuxième session à nouveau :
SQL-- Run this in the SECOND session
SELECT * FROM sample_accounts WHERE id = 10;La ligne est visible car la transaction a été validée.
Cette isolation empêche les autres utilisateurs de lire des données qui pourraient être annulées.
Choisissez un mode de transaction
Scénario | Mode recommandé |
|---|---|
Jobs ETL planifiés | Non-interactif : le commit ou le rollback automatique simplifie la gestion des erreurs. |
Séquences d'instructions fixes | Non-interactif : syntaxe plus simple, aucun commit manuel nécessaire. |
Validation des données avant commit | Interactif : inspectez les résultats et décidez s’il faut les commit |
Applications JDBC nécessitant un contrôle manuel | Interactif : modèles de transactions de base de données standard. |
Ressources supplémentaires
- Tutoriel : Coordonner les transactions entre les tables
- Transactions
- Commits de catalogue
- Niveaux d'isolation et conflits d'écriture
- Instruction composée ATOMIC (transactions non interactives): Exécutez plusieurs instructions SQL comme une seule transaction atomique avec commit et rollback automatiques.
- BEGIN TRANSACTION (transactions interactives): Commencer une transaction interactive avec contrôle manuel des validations (commit) et des annulations (rollback).
- COMMIT: COMMIT une transaction interactive et rendez toutes les modifications permanentes.
- ROLLBACK: Annulez une transaction interactive et ignorez toutes les modifications.