事务和乐观并发控制

适用范围: NoSQL

数据库事务提供一种安全且可预测的编程模型来处理数据的并发更改。 传统关系数据库(如 SQL Server)允许使用存储过程和触发器编写业务逻辑,然后将其发送到服务器,以便在数据库引擎中直接执行。

使用传统关系数据库时,需要处理两种不同的编程语言:非事务性应用程序编程语言,如 JavaScript、Python、C# 或 Java;和事务性编程语言(如 T-SQL)由数据库本机执行。

Azure Cosmos DB 中的数据库引擎支持完全符合 ACID(原子性、一致性、隔离、持久性)标准的事务,并提供快照隔离。 容器 逻辑分区 范围内的所有数据库作都以事务方式在由分区副本托管的数据库引擎内执行。 这些操作同时包括写入(更新逻辑分区内的一个或多个项)和读取操作。

下表列出了不同的作和事务类型:

运算 操作类型 单项或多项交易
插入(不带前/后触发器) 写入 单项事务
插入(带前/后触发器) 写入和读取 多项事务
替换(不带前/后触发器) 写入 单项事务
替换(带前/后触发器) 写入和读取 多项事务
更新插入(不带前/后触发器) 写入 单项事务
更新插入(带前/后触发器) 写入和读取 多项事务
删除(不带前/后触发器) 写入 单项事务
删除(带前/后触发器) 写入和读取 多项事务
执行存储过程 写入和读取 多项事务
系统开始执行合并程序 写入 多项事务
系统基于项的有效期 (TTL) 而发起的删除项执行 写入 多项事务
读取 读取 单项事务
更改源 读取 多项事务
分页读取 读取 多项事务
分页查询 读取 多项事务
在分页查询中执行 UDF 读取 多项事务

多项事务

Azure Cosmos DB 允许在 JavaScript 中编写 存储过程、触发器和用户定义的函数 和合并过程。 Azure Cosmos DB 以本机方式支持在其数据库引擎内执行 JavaScript。 可以在容器上注册存储过程、预先/发布触发器、用户定义的函数(UDF)和合并过程,并在 Azure Cosmos DB 数据库引擎中以事务方式执行它们。 通过采用 JavaScript 编写应用程序逻辑,可以直接使用 JavaScript 语言在数据库事务内自然表达异常处理基元的控制流、变量作用域、分配以及集成。

基于 JavaScript 的存储过程、触发器、UDF 和合并过程包含在环境 ACID 事务中,该事务在逻辑分区内的所有项目之间使用快照隔离。 在执行期间,如果 JavaScript 程序引发异常,则会中止并回滚整个事务。 生成的编程模型简单但功能强大。 JavaScript 开发人员在继续使用其自己熟悉的语言构造和库基元的同时,可以获得“持久”的编程模型。

直接在数据库引擎中执行 JavaScript 的能力可实现针对容器项的数据库操作的性能和事务性执行。 此外,由于 Azure Cosmos DB 数据库引擎本地支持 JSON 和 JavaScript,因此应用程序和数据库的类型系统之间没有不匹配的情况。

乐观并发控制

通过乐观并发控制(OCC),可以阻止丢失的更新和删除。 并发冲突的操作受数据库引擎的常规悲观锁定的限制,该引擎由拥有该项的逻辑分区托管。 当两个并发操作尝试更新逻辑分区中项的最新版本时,其中一个操作将获胜,另一个操作将失败。 但是,如果尝试同时更新同一项的一个或两个操作之前读取了该项的较旧值,数据库不知道这一个或两个冲突操作读取的值是否确实是该项的最新值。

幸运的是,在允许这两个操作进入数据库引擎内的事务边界之前,可以使用 OCC 检测这种情况。 OCC 可防止数据意外覆盖其他人所做的更改。 它还可以防止其他人意外覆盖你自己的更改。

使用 ETag 和 HTTP 标头实现乐观并发控制

存储在 Azure Cosmos DB 容器中的每个项都具有系统定义的 _etag 属性。 每次更新项时,_etag 的值都由服务器自动生成和更新。 _etag 可与客户端提供的 if-match 请求标头配合使用,使服务器能够决定是否可以条件性地更新某项。 如果标头的值 if-match 与服务器上的值 _etag 匹配,则会更新该项。 如果 if-match 请求标头值不再是最新值,则服务器会拒绝该操作,并提供“HTTP 412 前置条件失败”响应消息。 然后客户端可重新提取该项,以在服务器上获取该项的当前版本,或用该项自己的 _etag 值覆盖服务器中该项的版本。 此外,_etag 可以与 if-none-match 标头配合使用,以确定是否需要重新提取资源。

每次更新项时,项的 _etag 值都会发生更改。 对于替换项操作,必须在请求选项中显式表达 if-match。 有关示例,请参阅 GitHub 中的示例代码。 将对存储过程接触的所有写入项隐式检查 _etag 值。 如果检查到任何冲突,存储过程回退事务并引发异常。 通过此方法,将以原子方式应用存储过程中的所有写入内容或不应用任何写入内容。 这是应用程序重新应用更新并重试原始客户端请求的信号。

乐观并发控制和多区域分布

基于 Azure Cosmos DB 的通信协议层,项的并发更新受 OCC 限制。 对于为 单区域写入配置的 Azure Cosmos DB 帐户,Azure Cosmos DB 可确保要更新的项的客户端版本(或删除)与 Azure Cosmos DB 容器中的项版本相同。 这可确保你的写入内容不会被他人的写入内容意外覆盖,反之亦然。 在多用户环境中,乐观并发控制可防止意外删除或更新项的错误版本。 在这种情况下,可防止项出现令人痛恨的“丢失更新”或“丢失删除”问题。

在配置了“多区域写入”的 Azure Cosmos DB 帐户中,如果数据的 与本地区域中数据的 _etag 相匹配,则数据可以独立提交到次要区域_etag。 在次要区域中本地提交新数据后,数据会合并到中心区域或主要区域。 如果冲突解决策略将新数据合并到中心区域,则会使用新 _etag数据在多个区域复制。 如果冲突解决策略拒绝新数据,则次要区域回退到原始数据和 _etag

后续步骤

详细了解数据库事务和乐观并发控制: