Transactions

重要

写入 Unity Catalog 管理的 Iceberg 表的事务处于私密预览阶段。 要加入此预览版,请提交托管 Iceberg 表预览版注册表单

事务使您能够跨多个 SQL 语句和表来协调操作。 所有更改要么全部成功,要么全部回滚,确保跨操作和表的数据一致性。 事务包括 ACID 属性:原子性、一致性、隔离性和持久性。 请参阅Azure Databricks 上的 ACID 保障是什么?

事务可用于 存储过程SQL 脚本 来生成任务关键型仓库工作负荷。

以下示例展示了一个事务处理:

非交互式

BEGIN ATOMIC
  UPDATE accounts SET balance = balance - 100 WHERE id = 1;
  UPDATE accounts SET balance = balance + 100 WHERE id = 2;
  INSERT INTO audit_log VALUES (1, 2, 100, current_timestamp());
END;

交互

BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
INSERT INTO audit_log VALUES (1, 2, 100, current_timestamp());
COMMIT;

这三条语句将一起提交。 如果任何语句失败,所有更改都会回滚,Databricks 会终止事务且不会产生副作用。

有关事务的实际操作,请参阅 教程:跨表协调事务

要求

要运行跨越多个语句或多个表的事务:

  • 所有被写入的表必须:
    • 是 Unity 目录托管表 (Delta Lake 或 Iceberg)
    • 已启用 Catalog 提交
  • 使用支持的计算:
    • 对于 非交互式事务,请使用任何运行 Databricks Runtime 18.0 及更高版本的 SQL 仓库、 无服务器计算群集
    • 对于 交互式事务,请使用任何 SQL 仓库。
    • 对于OpenSharing 共享资产上的事务操作,请使用 Databricks Runtime 18.1 及更高版本。

事务模式

Azure Databricks支持两种事务模式:

模式 Syntax 提交 回退 最适用于
非交互式 原子复合语句 成功后自动执行 错误时自动回滚 固定序列、计划作业
交互 BEGIN TRANSACTION; COMMIT; 手动 手动 条件逻辑、验证和调试、JDBC、ODBC、PyODBC

有关这两种模式的详细语法、示例和使用模式,请参阅 事务模式

支持的操作

可以在事务中使用下列操作:

运算 说明
SELECT(子选择) 查询数据和验证结果
VALUES 子句 生成测试数据或常量值
INSERT (包括所有变体) 添加新行
UPDATE 修改现有行
COPY INTO 将数据从文件加载到 Delta 表中
DELETE FROM 删除行
MERGE INTO 结合插入、更新和删除的更新插入模式
USE CATALOGUSE SCHEMA 为事务中的各语句设置当前目录或架构
EXECUTE IMMEDIATE 执行在运行时动态构造的 SQL 语句
DESCRIBE TABLE 返回有关表的元数据,例如其列和属性
SHOW COLUMNS 列出表格中的列
GETDIAGNOSTICS 语句 检索诊断信息,例如活动事务状态或受最新语句影响的行数

支持的读取源和写入接收器

事务允许您从 Unity Catalog 中的表(Delta Lake 和 Iceberg)、流表、视图和物化视图中读取数据。

由于具备 ACID 保证,Delta Lake 和 Iceberg 等开放表格式在事务中既可作为读取源,也可作为写入目标。 若要从非事务源读取,请使用 allow_nontransactional_read 提示。 请参阅 从非事务源读取示例:非事务性读取

从非事务源读取

警告

非事务性读取不可重复。 事务期间对源数据的并发更改可能会导致读取不一致。

事务允许你从非事务性源中读取。 非事务源包括使用 Parquet、Avro、CSV 和 JSON 文件格式的外部表,以及 使用 JDBC 的联合表。 若要读取非事务源,请按名称引用源并使用 allow_nontransactional_read 提示。

在事务中,还可以查询 information_schema

可以使用 read_files 表值函数直接读取文件。

不支持基于路径的访问。 如果直接按路径引用文件,例如 FROM parquet.`/path/to/data`,事务会失败并显示 PATH_BASED_ACCESS 错误。

下面的代码示例演示如何使用 JSON 对外部表使用提示:

BEGIN TRANSACTION;
-- Non-transactional source, hint required
INSERT INTO transactional_table
SELECT col1, col2
FROM external_json_table
WITH (allow_nontransactional_read = true);

COMMIT;

示例:非事务性读取

以下示例演示如何使用 Parquet 从外部表进行非事务性读取。 此示例要求你具有具有读取和写入访问权限的现有外部位置。

请参阅连接到Azure Data Lake Storage Gen2(ADLS Gen2)外部位置

若要将 Parquet 源注册为命名外部表,请运行以下命令:

CREATE TABLE main.default.external_parquet_table
USING PARQUET
LOCATION 'abfss://my-container@my-storage-account.dfs.core.windows.net/path/to/data'; -- existing external location

若要在事务中使用 Delta Lake 读取非事务性 Parquet 数据源和托管表,请运行以下命令:

BEGIN ATOMIC
-- Non-transactional source, hint required
INSERT INTO transactional_table
SELECT col1, col2
FROM external_parquet_table
WITH (allow_nontransactional_read = true);

-- Managed table source, no hint is required
INSERT INTO another_table
SELECT * FROM managed_delta_table;
END;

事务隔离

事务允许在所有语句中进行可重复读取。 当您在事务中访问表时,Azure Databricks 会在首次访问时捕获该表的一致快照。 该表的所有后续读取都使用此快照,因此即使其他用户同时修改同一个表,读取仍保持一致。

在以下示例中,事务中针对 products 的第一个查询捕获了一致快照:

非交互式

BEGIN ATOMIC
  SELECT * FROM products WHERE product_id = 1001;
  SELECT * FROM products WHERE product_id = 1001;
END;

交互

BEGIN TRANSACTION;
SELECT * FROM products WHERE product_id = 1001;
SELECT * FROM products WHERE product_id = 1001;
COMMIT;

然后,假设另一个用户在第二次查询开始前并发更新了 product_id = 1001 行:

UPDATE products SET price = 29.99 WHERE product_id = 1001;

由于快照是在首次访问时创建的,因此对 products 的第二次查询返回的是原始行,而不是更新后的行。

冲突检测和并发

Azure Databricks 使用乐观并发控制。 事务在无锁状态下进行,冲突在提交时被检测到。 提交时,Azure Databricks检查其他事务在事务开始后是否修改了相同的数据。 如果存在冲突,则事务会失败。 对于非交互式事务,回滚也会自动发生。 对于交互式事务,必须在开始新事务之前显式运行 ROLLBACK 以清除事务状态。

非交互式事务支持行级并发。 在目标表上启用 行级别并发 时,两个事务可以修改同一数据文件中的不同行,而不会发生冲突。

交互式事务支持表级并发。

冲突方案

情景 说明
写-写冲突 两个事务更新或删除相同的行。
读写冲突 另一个事务修改了您事务读取的行。 仅适用于可序列化隔离。
幻读冲突 另一个事务添加了与您当前事务读取的谓词相匹配的新行。 同时适用于 WriteSerializable 和 Serializable 隔离级别。
元数据冲突 另一个事务更改了表架构或属性。

有关事务的隔离级别和冲突解决的更多详细信息,请参阅 事务模式。 有关 Azure Databricks 上 Delta Lake 表的隔离级别和写入冲突行为的信息,请参阅 Azure Databricks 上的优化建议

事务在 Delta 日志中的显示方式

每个成功的事务都会作为单条记录出现在表的 Delta 日志中,无论该事务中执行了多少条单独的语句。 这样可以形成清晰的审计轨迹,并简化回滚操作。

事务中的单个操作在事务的 Delta 日志条目中可用作 JSON 元数据。

错误处理和回滚

下表描述了这两种事务类型的错误回滚方式:

情景 非交互式事务的行为 交互式事务的行为
语句失败 引发错误的任何语句都会导致立即自动回滚。 如果会话仍然处于活动状态,则必须显式运行 ROLLBACK 以放弃更改。
验证逻辑或业务规则失败 使用 SIGNAL 来引发异常并触发自动回滚。 运行 ROLLBACK 以放弃更改。
会话断开连接 事务会自动回滚。 事务会自动回滚。
超时 总持续时间超过 48 小时后将自动回滚。 在连续 10 分钟无活动或总持续时间达到 48 小时后,自动回滚(请参阅 限制)。 事务在没有副作用的情况下终止,但是,如果会话仍然处于活动状态,则必须显式运行 ROLLBACK 才能清除事务状态。

对于交互式事务,您可以使用 ROLLBACK 语句显式回滚。 这样,您就可以根据验证逻辑或业务规则丢弃这些更改,或者在语句执行失败但会话仍保持活动状态后丢弃这些更改。

最佳做法

遵循这些做法来减少冲突并优化事务性能。

避免冲突

  • 保持事务简短:长时间运行的事务会增加冲突可能性,并占用资源时间更长。
  • 尽早验证:在事务开始时检查先决条件,以实现快速失败。
  • 使用 BEGIN ATOMIC 实现行级并发:非交互式事务(BEGIN ATOMIC ... END;)在行级检测冲突,与交互式事务采用的表级检测相比,可减少冲突。 请参阅 非交互式事务
  • 生成重试逻辑:由于冲突,事务随时可能失败。 在应用程序中生成重试逻辑,并使用新数据重试失败的事务。
  • 使用回滚启动每个交互式会话:在交互式会话开始时运行 ROLLBACK 以清除任何预先存在的事务状态。

使用来自不同客户端的事务

事务能够跨各种客户端接口运行。

局限性

以下限制适用于交易:

限度 说明
交互式事务冲突 交互式事务 (BEGIN TRANSACTION; ... COMMIT;)使用比非交互式事务更保守的冲突检测,并且可以在表级别发生冲突,但未从目标表读取的操作除外 INSERT 。 当行级冲突检测至关重要时,请使用非交互式事务(ATOMIC 复合语句)。 请参阅 非交互式事务
写入目标 您只能向已启用 catalogManaged 表功能的 Unity Catalog 管理的 Delta 或 Iceberg 表写入数据。 请参阅 目录提交
不支持 DDL 操作 在事务之外运行 DDL 操作,例如CREATE TABLEALTER TABLEDROP TABLE。 有关事务支持的操作,请参阅 支持的操作
不支持某些元数据操作 无论协议如何,某些元数据操作在事务内都不起作用。 这包括基于 Thrift RPC 的元数据调用(如 JDBC DatabaseMetaData 方法和 ODBC 目录函数)、基于 SQL 的命令,这些命令枚举对象(如 SHOW TABLESSHOW DATABASES)以及 SELECT 针对系统表的查询。 在事务之外运行这些元数据操作。
COPY INTO 并发 如果另一个COPY INTO命令同时运行以写入同一个表并首先提交,则运行COPY INTO命令的事务将失败。
MERGE 的行级并发 在 AWS GovCloud 或单用户(专用)集群上,不支持 MERGE 操作的行级并发。 在这些平台上, MERGE 操作使用表级并发。 请参阅 行级并发
表和视图限制 一个事务最多可读写合计 100 张表,并可读取最多 100 个视图。 每个表在事务中最多可进行 100 次中间提交。
不支持时间旅行 不能在事务中使用 时间旅行
空闲超时 交互式事务在闲置 10 分钟后将回滚。 事务在没有副作用的情况下终止,但是,如果会话仍然处于活动状态,则必须显式运行 ROLLBACK 才能清除事务状态。
谱系 事务会在每次读写操作发生时生成世系。 即使事务回滚,世系事件也会保留。
最大持续时间 所有事务在总持续时间达到 48 小时后将自动回滚。 对于交互式事务,事务将终止而不产生副作用,但是,如果会话仍然处于活动状态,则必须显式运行 ROLLBACK 以清除事务状态。
OpenSharing 共享表要求 OpenSharing 提供程序必须 共享一个表 WITH HISTORY ,以允许收件人在表中运行事务。 收件人可以使用任何类型的计算运行事务。
OpenSharing 接收方计算限制 Azure Databricks 接收方仅可在共享视图、具体化视图、流式表和非 Iceberg 外表上运行事务。 与提供商相同的Azure Databricks帐户中的收件人必须使用共享或无服务器计算。 其他帐户中的收件人必须使用无服务器计算。
OpenSharing 源表冲突 OpenSharing 接收方无法在单个事务中同时引用共享视图和共享表(两者引用同一个源表)。

其他资源