【问题标题】:How to do lock item in DynamoDB during update?更新期间如何在 DynamoDB 中锁定项目?
【发布时间】:2022-08-21 08:18:50
【问题描述】:

我正在使用大量并发更新请求测试 DynamoDB,但我有一些疑问。

例如: 在一个金融交易系统中,我有一个名为 Account 的表和一个名为 Transactions 的表。

Accounts:
    id: string
    balance: Number

Transactions
   id: Number
   amount: Number
   balanceAfter: Number
   accountId: string

因此,在执行借记交易时,我会更新 Account 表中的余额,并在交易后使用账户余额创建交易。

如果帐户的余额为 100,我同时执行两个 50 的事务,则帐户余额将为 50 而不是 0,并且数据库中有两个事务,余额为 50。

  1. 如何锁定 DynamoDB 项目以进行并发更新以避免双重支出? (类似于关系数据库中的 TRANSACTION)

  2. 运行 UPDATE 后从 DynamoDB 获取更新项目的最安全方法是什么?

    编码:

    <?php
    
    require \'./vendor/autoload.php\';
    
    use Aws\\DynamoDb\\DynamoDbClient;
    use Aws\\Credentials\\CredentialProvider;
    
    function executeDebitTransaction($accountId, $transactionAmount) 
    {
      $provider = CredentialProvider::defaultProvider();
    
      $client = DynamoDbClient::factory(array(
        \'version\' => \'2012-08-10\',
        \'credentials\' => $provider,
        \'region\'  => \'sa-east-1\'
      ));
    
      $response = $client->getItem(array(
        \'TableName\' => \'Accounts\',
        \'Key\' => array(
            \'id\' => array( \'S\' => $accountId ))
        )
      );
      
      $currentBalance = $response[\'Item\'][\'balance\'][\'N\'];
      
      $newbalance = (string)((int)$currentBalance - (int)$transactionAmount);
      
      $response = $client->updateItem(array(
        \'TableName\' => \'accounts\',
          \'Key\' => array(
            \'id\' => array( \'S\' => $accountId )
          ),
        \'ExpressionAttributeValues\' =>  array (
          \':amount\' => array(\'N\' => $transactionAmount),
        ),
        \'UpdateExpression\' => \'SET balance = balance - :amount\'
      ));
      
      // Generate random ID
      $id = (string)(random_int(1, 1000000000));
    
      $client->putItem(array(
        \'TableName\' => \'Transactions\',
        \'Item\' => array(
          \'id\' => array(\'N\' => $id),
          \'amount\' => array(\'N\' => $transactionAmount),
          \'balanceAter\' => array(\'N\' => $newbalance),
          \'accountId\' => $transactionAmount
        )
      ));
    }
    
    $accountId = \'A1469CCD-10B8-4D31-83A2-86B71BF39EA8\';
    $debitAmount = \'50\';
    executeDebitTransaction($accountId, $debitAmount);
    

    以很少的并发运行此脚本可以完美运行,但是当我增加并行度时,我开始遇到问题。

标签: php amazon-web-services amazon-dynamodb


【解决方案1】:

使用乐观锁做了一些测试,我得到了很好的结果。

回购:https://github.com/thalyswolf/dynamo-lock/blob/main/src/Repository/AccountRepositoryDynamoWithOptimisticLock.php

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-08
    • 2014-11-22
    • 2016-02-24
    • 2022-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多