c# - DynamoDB - 如何使用 ServiceStack.Aws 实现乐观锁定
问题描述
目前,我正在使用 ServiceStack.Aws v5.9.0 与 DynamoDB 进行通信。我已经使用 PutItem 来创建和更新项目,而不会在并发处理的情况下预期数据丢失。
public class Customer
{
[HashKey]
public int CustomerId { get; set; }
[AutoIncrement]
public int SubId { get; set; }
public string CustomerType { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
...//and hundreds of fields here
}
public class CustomerDynamo
{
private readonly IPocoDynamo db;
//Constructor
public CustomerDynamo()
{
var dynamoClient = new AmazonDynamoDBClient(_region);
var entityType = typeof(Customer);
var tableName = entityType.Name;
entityType.AddAttributes(new AliasAttribute(name: tableName));
db = new PocoDynamo(dynamoClient) { ConsistentRead = true }.RegisterTable(tableType: entityType);
}
public Customer Update(Customer customer)
{
customer.ModifiedDate = DateTime.UtcNow;
db.PutItem(customer);
return customer;
}
}
在需要更新客户数据的每个服务/异步任务中都会调用上述 Update 方法。参考这篇 AWS 的文章,我决定实现 Optimistic Locking 来避免并发请求的问题。 https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBContext.VersionSupport.html
假设 VersionNumber 将是 Optimistic Locking 的关键。所以我将 VersionNumber 添加到 Customer 模型中。
public class Customer
{
[HashKey]
public int CustomerId { get; set; }
[AutoIncrement]
public int SubId { get; set; }
public string CustomerType { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
...//and hundreds of fields here
[DynamoDBVersion]
public int? VersionNumber { get; set; }
}
- 结果是 VersionNumber 未更新,而应自动递增。我认为这只是因为 PutItem 将覆盖整个现有项目。这个对吗?
- 我想我需要在 Update 方法中从 PutItem 更改为 UpdateItem。问题是如何动态生成表达式以与 UpdateItem 一起使用?
提前感谢您的帮助!
更新:
感谢@mythz提供有关 DynamoDBVersion 属性的有用信息。然后我尝试删除 DynamoDBVersion 并使用 PocoDynamo 的 UpdateExpression 如下
public Customer Update(Customer customer)
{
customer.ModifiedDate = DateTime.UtcNow;
var expression = db.UpdateExpression<Customer>(customer.CustomerId).Set(() => customer);
expression.ExpressionAttributeNames = new Dictionary<string, string>()
{
{ "#Version", "VersionNumber" }
};
expression.ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
{
{ ":incr", new AttributeValue { N = "1" } },
{ ":zero", new AttributeValue { N = "0" } }
};
expression.UpdateExpression = "SET #Version = if_not_exists(#Version, :zero) + :incr";
if (customer.VersionNumber.HasValue)
{
expression.Condition(c => c.VersionNumber == customer.VersionNumber);
}
var success = db.UpdateItem(expression);
}
但是除了 VersionNumber 之外,没有保存更改
解决方案
这[DynamoDBVersion]
是一个 AWS Object Persistence Model 属性,用于 AWS 的DynamoDBContext
not for PocoDynamo。即[DynamoDB*]
PocoDynamo 使用的唯一属性是[DynamoDBHashKey]
,[DynamoDBRangeKey]
所有其他[DynamoDB*]
属性都适用于 AWS 的对象持久性模型库。
需要时,您可以通过以下方式访问 AWS IAmazonDynamoDB
:
var db = new PocoDynamo(awsDb);
var awsDb = db.DynamoDb;
以下是有关 PocoDynamo 的 UpdateItem API可能相关的文档。
推荐阅读
- mysql - 错误:无法将用户序列化到会话中。(使用 mysql)完成(错误,配置文件)
- java - 避免使用 servlet 使用相同 ID 进行多次注册
- reactjs - 运行 npm audit fix 后,ERESOLVE 无法解析依赖关系树
- reactjs - 具有持久本地数据库的渐进式 Web 应用程序
- django - 如何管理由 Django 中的中央身份验证服务器身份验证的客户端服务器上的用户相关操作
- php - 如何在查询生成器中加入 2 个子字符串索引?
- vue.js - 嵌套 v-for;从 Firestore 加载并访问每个创建的 v-text-field 中的更改
- windows - 无法在 QT 中安装图表
- html - 使用 quill-delta-to-html 插件在 Quill 编辑器中支持 Shift+Enter 以呈现自定义 HTML
- reactjs - 如何限制 React 钩子函数中选定项目的数量