重要
写入 Unity Catalog 托管 Delta 表的事务目前处于公共预览阶段。
写入 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;
这三个语句一起提交。 如果任何语句失败,则所有更改回滚,Databricks 将终止事务而不产生副作用。
有关事务的实际操作,请参阅 教程:跨表协调事务。
要求
要运行跨多个语句或多个表的事务:
- 所有被写入的数据表都必须:
- 是 Unity 目录托管表 (Delta 或 Iceberg)
- 已启用目录管理的提交
- 使用支持的计算:
事务模式
Azure Databricks 支持两种事务模式:
| 模式 | Syntax | 提交 | 回退 | 最适用于 |
|---|---|---|---|---|
| 非交互式 | ATOMIC 复合语句 | 成功后自动执行 | 错误时自动处理 | 固定序列、计划作业 |
| 交互 | BEGIN TRANSACTION; COMMIT; | 手动 | 手动 | 条件逻辑、验证和调试、JDBC、ODBC、PyDBC |
有关这两种模式的详细语法、示例和使用模式,请参阅 事务模式。
支持的操作
可以在事务中使用下列操作:
| 运算 | 说明 |
|---|---|
| SELECT | 查询数据和验证结果 |
| VALUES 子句 | 生成测试数据或常量值 |
| INSERT (包括所有变体) | 添加新行 |
| UPDATE | 修改现有行 |
COPY INTO |
将数据从文件加载到 Delta 表中 |
| DELETE FROM | 删除行 |
| MERGE INTO | 结合插入、更新和删除操作的 Upsert 模式 |
读取事务中的源
事务可以从 Unity Catalog 表(Delta 和 Iceberg)、流式表、视图和物化视图中读取。 若要从非事务源读取,请使用 allow_nontransactional_reads 提示。
从非事务源读取
若要 使用 JDBC 从非事务性数据源(如 Parquet 文件、Avro 文件和联合表)读取,请使用 allow_nontransactional_reads 提示,如以下示例所示:
BEGIN TRANSACTION;
-- Read from a non-transactional Parquet source
INSERT INTO transactional_table
SELECT col1, col2
FROM parquet.`/path/to/data`
WITH (allow_nontransactional_reads = true);
-- Read from a managed Delta table (no hint needed)
INSERT INTO another_table
SELECT * FROM managed_delta_table;
COMMIT;
警告
非事务性读取不可重复。 事务期间对源数据的并发更改可能会导致读取不一致。
事务隔离
事务在所有语句中提供可重复读取。 在事务中访问表时,Azure Databricks 在首次访问时捕获该表的一致快照。 该表的所有后续读取都使用此快照,因此即使其他用户同时修改同一个表,读取仍保持一致。
例:
BEGIN TRANSACTION;
-- First access to products table captures snapshot
SELECT * FROM products WHERE product_id = 1001;
-- Another user updates product 1001
-- Still reads the same snapshot (repeatable read)
SELECT * FROM products WHERE product_id = 1001;
COMMIT;
冲突检测和并发
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 语句来显式地进行回滚。 在根据验证逻辑或业务规则放弃更改时,或者当语句失败但会话仍保持活动状态时,这样的做法非常有用。
最佳做法
遵循这些做法来减少冲突并优化事务性能。
避免冲突
- 保持事务简短:长时间运行的事务会增加冲突可能性,并占用资源时间更长。
- 提前验证:在事务开始时检查前置条件以便快速失败。
- Databricks 建议对大多数用例使用非交互式事务:非交互式事务使用行级并发。 请参阅 非交互式事务。
- 对冲突重试:发生冲突时,请使用新数据重试事务。
使用来自不同客户端的事务
事务能够跨各种客户端接口运行。
-
SQL 编辑器和笔记本:直接在 SQL 单元格中使用
BEGIN ATOMIC ... END;或BEGIN TRANSACTION; ... COMMIT;语法,或在 Python/Scala 笔记本中使用spark.sql()。 请参阅 事务模式。 -
JDBC 应用程序:将 JDBC API 方法(
setAutoCommit(false)、commit())rollback()与 Databricks JDBC 驱动程序 版本 3.0.5 及更高版本配合使用。 请查看 示例:使用事务。 有关事务中不支持的 JDBC 操作的列表,请参阅 不支持的 JDBC 操作。 - ODBC 应用程序:使用 Databricks ODBC 驱动程序 版本 2.10.0 及更高版本。 有关事务中不支持的 ODBC 操作的列表,请参阅 不受支持的 ODBC 操作。
-
Python 应用程序:将 Databricks SQL 连接器与
autocommit=False.. 请参阅 用于 Python 的 Databricks SQL 连接器。 有关事务中不支持的 Python 连接器操作的列表,请参阅 不支持的 Python 连接器操作。 - 语句执行 API:通过 API 调用使用 SQL 语法运行事务。 请参阅 “与语句执行 API 一起使用”。
局限性
以下限制适用于跨多个表的事务:
| 限度 | 说明 |
|---|---|
| 交互式事务冲突 | 交互式事务 (BEGIN TRANSACTION; ... COMMIT;)使用比非交互式事务更保守的冲突检测,并且可以在表级别发生冲突,但未从目标表读取的操作除外 INSERT 。 当行级别冲突检测非常重要时,请使用非交互式事务(ATOMIC 复合语句)。 请参阅 非交互式事务。 |
| 写入目标 | 只能写入 Unity Catalog 管理的 Delta 或 Iceberg 表,这些表必须启用catalogManaged表功能。 请参阅 目录管理的提交。 |
| 仅限 DML 操作 | 事务支持SELECT、INSERT、UPDATE、DELETE、COPY INTO和MERGE。 在事务之外运行 DDL 操作,例如CREATE TABLE、ALTER TABLE或DROP TABLE。 |
| 不支持元数据操作 | 无论协议如何,元数据操作都无法在事务中运行。 这包括基于 Thrift RPC 的元数据调用(如 JDBC DatabaseMetaData 方法和 ODBC 目录函数)、基于 SQL 的命令(SHOW TABLES、 SHOW DATABASES、 DESCRIBE TABLE)以及 SELECT 针对表或系统表的 information_schema 查询。 在事务之外运行元数据操作。 |
COPY INTO 并发 |
如果另一个COPY INTO命令同时运行以写入同一个表并首先提交,则运行COPY INTO命令的事务将失败。 |
| 不支持流式写入 | 不支持在流式处理表上执行事务性写入。 |
| 不支持 RLS 和 CLM 表 | 具有 行筛选器和列掩码的表 不能参与事务。 |
| 表和视图限制 | 事务可以读取或写入最多 100 张表的组合,并且可以最多读取 100 个视图。 每个表在事务中最多可以有多达 100 次中间提交。 |
| 不支持时间旅行 | 不能在事务中使用 时间旅行 。 |
| 空闲超时 | 交互式事务在 10 分钟不活动后回滚。 事务在没有副作用的情况下终止,但是,如果会话仍然处于活动状态,则必须显式运行 ROLLBACK 才能清除事务状态。 |
| 最大持续时间 | 所有事务在总持续时间 48 小时后自动回滚。 对于交互式事务,事务将终止而不产生副作用,但是,如果会话仍然处于活动状态,则必须显式运行 ROLLBACK 以清除事务状态。 |
| Delta Sharing 共享表要求 | 增量共享提供程序必须 共享一个表 WITH HISTORY ,以允许收件人在表中运行事务。 收件人可以使用任何类型的计算运行事务。 |
| Delta Sharing 接收方计算限制 | Azure Databricks 收件人只能对共享视图、具体化视图、流式处理表和非 Iceberg 外表运行事务。 与提供程序相同的 Azure Databricks 帐户中的收件人必须使用共享或无服务器计算。 其他帐户中的收件人必须使用无服务器计算。 |
| Delta Sharing源表冲突 | Delta共享的收件人不能在单个事务中同时引用共享视图和共享表,因为它们引用的是同一个源表。 |