View a markdown version of this page

乐观锁(使用版本号) - Amazon DynamoDB

乐观锁(使用版本号)

乐观锁是一种在写入时检测冲突而不是防止冲突的策略。每个项目都包含一个版本属性,其值会随着每次更新而增加。更新项目时,您需要包含一个条件表达式,用于检查版本号是否与应用程序上次读取的值匹配。如果在这个期间其他进程修改了该项目,则条件失败并且 DynamoDB 返回 ConditionalCheckFailedException

使用乐观锁的情况

乐观锁非常适合用于以下情况:

  • 多个用户或进程可能会更新同一个项目,但冲突并不频繁。

  • 对于应用程序来说,重试失败写入的成本较低。

  • 您需要避免管理分布式锁的开销和复杂性。

常见的示例包括电子商务库存更新、协作编辑平台和金融交易记录。

权衡

高争用率下的重试开销

在高并发环境中,发生冲突的可能性会增加,进而可能导致更高的重试次数和写入成本。

实施复杂性

向项目添加版本控制和处理有条件检查,会增加应用程序逻辑的复杂性。适用于 Java 的 AWS SDK v2 增强版客户端通过 @DynamoDbVersionAttribute 注解提供内置支持,这可以自动为您管理版本号。

模式设计

每个项目中包含一个版本属性。以下提供了一个简单的架构设计:

  • 分区键:每个项目的唯一标识符(例如 ItemId)。

  • 属性:

    • ItemId – 项目的唯一标识符。

    • Version – 表示项目版本号的整数。

    • QuantityLeft – 项目的剩余库存。

首次创建项目时,Version 属性设置为 1。每次进行更新时,版本号增加 1。

ItemID(分区键) 版本 QuantityLeft
Bananas 1 10
Apples 1 5
Oranges 1 7

实现

要实施乐观锁,请按照以下步骤操作:

  1. 读取项目的当前版本。

    def get_item(item_id): response = table.get_item(Key={'ItemID': item_id}) return response['Item'] item = get_item('Bananas') current_version = item['Version']
  2. 使用检查版本号的条件表达式更新项目。

    def update_item(item_id, qty_bought, current_version): try: response = table.update_item( Key={'ItemID': item_id}, UpdateExpression="SET QuantityLeft = QuantityLeft - :qty, Version = :new_v", ConditionExpression="Version = :expected_v", ExpressionAttributeValues={ ':qty': qty_bought, ':new_v': current_version + 1, ':expected_v': current_version }, ReturnValues="UPDATED_NEW" ) return response except ClientError as e: if e.response['Error']['Code'] == 'ConditionalCheckFailedException': print("Version conflict: another process updated this item.") raise
  3. 使用新的读取进行重试来处理冲突。

    每次重试都需要进行额外的读取操作,因此请限制重试的总次数。

    def update_with_retry(item_id, qty_bought, max_retries=3): for attempt in range(max_retries): item = get_item(item_id) try: return update_item(item_id, qty_bought, item['Version']) except ClientError as e: if e.response['Error']['Code'] != 'ConditionalCheckFailedException': raise print(f"Retry {attempt + 1}/{max_retries}") raise Exception("Update failed after maximum retries.")

对于 Java 应用程序,适用于 Java 的 AWS SDK v2 增强版客户端通过 @DynamoDbVersionAttribute 注解提供内置乐观锁支持,这可以自动为您管理版本号。

有关条件表达式的更多信息,请参阅 DynamoDB 条件表达式 CLI 示例