将任何实体上的版本属性保存到
AWS DynamoDB数据库,它仅是表示实体已修改次数的数字表示。 首次创建实体时,可以将其设置为1,然后在每次更新时递增。
好处是立竿见影的-指示实体已被修改的次数,可用于审核实体。 此外,还有一种额外的用途是乐观锁定 ,其中仅当更新实体的持有者具有正确版本的实体时才允许更新实体。
这篇文章将详细介绍如何通过AWS开发工具包2的DynamoDB相关库引入此类字段
模型
考虑一个名为“旅馆”的模型,该模型将持久化到发电机数据库中。 在Kotlin中,可以使用以下数据类表示它:
data class Hotel(
val id: String = UUID.randomUUID().toString(),
val name: String,
val address: String? = val address: String? = null ,
val state: String? = val state: String? = null ,
val zip: String? = val zip: String? = null ,
val version: Long = 1L )
此模型中引入了一个version字段,其初始值为1。其目的是按原样保存此字段,然后让dynamo在保存该实体时自动管理该字段的增量。
随着此模型中字段的更改,我希望按照以下内容更新版本:
DynamoDB的本地版本
使DynamoDB在本地计算机上运行非常有用,这样就不必在AWS中创建真正的DynamoDB表。
有多种方法可以做到这一点。 一种是使用的docker版本
DynamoDB Local ,可以通过以下方式启动以侦听端口4569:
amazon/dynamodb-local: docker run -p 4569 : 8000 amazon/dynamodb-local: 1.13
我个人的喜好是使用localstack ,站点上的说明有不同的启动方式。 我通常使用docker-compose来启动它。 在DynamoDB Local上使用localstack的原因之一是localstack提供了一套全面的AWS服务用于本地测试,而不仅仅是DynamoDB。
快速演示
我在这里的 github仓库中有完整的代码–
https://github.com/bijukunjummen/boot-with-dynamodb
使用dynamoDB的本地版本启动应用程序后,可以使用以下httpie请求创建实体:
http : 9080 /hotels id= 4 name=name address=address zip=zip state=OR
响应,其中version字段设置为1:
{
"address" : "address" ,
"id" : "4" ,
"name" : "name" ,
"state" : "OR" ,
"version" : 1 ,
"zip" : "zip" }
然后,如果实体的名称已更新:
http PUT : 9080 /hotels/ 4 name=name1 address=address zip=zip state=OR version= 1
版本字段将更新为2,依此类推:
{
"address" : "address" ,
"id" : "4" ,
"name" : "name1" ,
"state" : "OR" ,
"version" : 2 ,
"zip" : "zip" }
还要注意,如果在更新期间提供了错误的版本号,则调用将失败,因为使用此版本字段存在乐观锁定。
实施版本字段
实现版本字段取决于DynamoDB提供的功能强大的UpdateItem API。 UpdateItem API的功能之一是它包含一个“ UpdateExpression”,它是一个dsl,它显示了应如何更新不同的Dynamo属性。
对AWS DynamoDB的原始请求如下所示:
{
"TableName" : "hotels" ,
"Key" : {
"id" : {
"S" : "1"
}
},
"UpdateExpression" : "\nSET #name=:name,\n #state=:state,\naddress=:address,\nzip=:zip\nADD version :inc\n " ,
"ExpressionAttributeNames" : {
"#state" : "state" ,
"#name" : "name"
},
"ExpressionAttributeValues" : {
":name" : {
"S" : "testhotel"
},
":address" : {
"S" : "testaddress"
},
":state" : {
"S" : "OR"
},
":zip" : {
"S" : "zip"
},
":inc" : {
"N" : "1"
}
} }
从文章角度看,特别关注“ ADD版本:inc”,该表达式告诉AWS DynamoDB将版本的值增加“:inc”值,该值使用“ ExpressionAttributeValues”和“ 1”单独提供。 以json格式处理原始API令人生畏,这就是AWS提供的软件开发套件(SDK)的来源,适用于Java 2的AWS开发工具包是对AWS开发工具包的重写,其重点是使用最新的Java功能和非通过线路阻塞IO。 使用适用于Java 2的AWS开发工具包,“ UpdateItem”如下所示(使用Kotlin代码):
val updateItemRequest = UpdateItemRequest.builder()
.tableName(TABLE_NAME)
.key(
mapOf(
ID to AttributeValue.builder().s(hotel.id).build()
)
)
.updateExpression(
"" "
SET #name=:name,
#state=:state,
address=:address,
zip=:zip
ADD version :inc
"" "
)
.conditionExpression( "version = :version" )
.expressionAttributeValues(
mapOf(
":${NAME}" to AttributeValue.builder().s(hotel.name).build(),
":${ZIP}" to AttributeValue.builder().s(hotel.zip).build(),
":${STATE}" to AttributeValue.builder().s(hotel.state).build(),
":${ADDRESS}" to AttributeValue.builder().s(hotel.address).build(),
":${VERSION}" to AttributeValue.builder().n(hotel.version.toString()).build(),
":inc" to AttributeValue.builder().n( "1" ).build()
)
)
.expressionAttributeNames(
mapOf(
"#name" to "name" ,
"#state" to "state"
)
)
.build() val updateItem: CompletableFuture<UpdateItemResponse> = dynamoClient.updateItem(updateItemRequest) return Mono.fromCompletionStage(updateItem)
.flatMap {
getHotel(hotel.id)
}
高亮显示的行具有“ Update Expression”,其中所有现有字段均设置为新值,并且version属性增加了1。关于此调用的另一件事要注意的是“ conditionExpression”,这实际上是告诉DynamoDB更新的一种方式。如果条件匹配,则为属性;在此特定情况下,如果版本的现有值匹配,则为属性。 这提供了一种支持乐观锁定记录的巧妙方法。
结论
这里有很多细节–感受它的最简单方法是尝试在我的github存储库中找到的代码– https://github.com/bijukunjummen/boot-with-dynamodb 。 自述文件提供了有关如何在本地环境中运行它的详细信息。
AWS DynamoDB提供了一种巧妙的方法来管理实体上的版本字段,确保对它们进行原子更新,并为它们提供了一种用于乐观锁定的方法
翻译自: https://www.javacodegeeks.com/2020/05/aws-dynamodb-version-field-using-aws-sdk-for-java-2.html