DynamoDBMapper 仅在唯一时保存项目
我正在尝试根据两个不同列的组合使表中的项目保持唯一.
I'm trying to keep items in my table unique based on a combination of two different columns.
我有一个 instanceId 和 imageId 列(以及其他列)并基于 Stackoverflow 上的几篇帖子 和 AWS 论坛 以下应该可以吗?
I have an instanceId and imageId column (along with others) and based on a couple of posts on Stackoverflow and AWS Forums the below should work?
public void saveUnique(Server server) {
DynamoDBSaveExpression saveExpression = new DynamoDBSaveExpression();
Map<String, ExpectedAttributeValue> expectedAttributes =
ImmutableMap.<String, ExpectedAttributeValue>builder()
.put("instanceId", new ExpectedAttributeValue(false))
.put("imageId", new ExpectedAttributeValue(false))
.build();
saveExpression.setExpected(expectedAttributes);
saveExpression.setConditionalOperator(ConditionalOperator.AND);
try {
mapper.save(server, saveExpression);
} catch (ConditionalCheckFailedException e) {
//Handle conditional check
}
}
但是,每次我尝试保存重复项(相同的 instanceId 和 imageId)时,它都会成功保存到数据库中.
However every time I try and save a duplicate item (same instanceId and imageId) it's successfully being saved into the database.
我还有什么遗漏吗?
编辑 R.E notionquest 答案
更新到下面的答案.
我有一项工作,每分钟运行一次,轮询 API.API 的响应表示为 Server
POJO.Server
有一个名为instanceId
的属性.
I have a job that runs once a minute polling an API. The response from the API is represented as a Server
POJO. The Server
has an attribute named instanceId
.
我想确保如果具有该 instanceId
的 Server
已经在数据库中,请不要保存它.
I want to make sure that if a Server
with that instanceId
is already in the database, don't save it.
Server
对象还有一个id
属性,它被设置为表的主键.
The Server
object has another attribute of id
which is set as the table primary key.
public void saveUnique(Server server) {
DynamoDBSaveExpression saveExpression = new DynamoDBSaveExpression();
Map<String, ExpectedAttributeValue> expected = new HashMap<>();
expected.put("instanceId", new ExpectedAttributeValue(new AttributeValue(server.getInstanceId())).withComparisonOperator(ComparisonOperator.NE));
saveExpression.setExpected(expected);
try {
mapper.save(server, saveExpression);
} catch (ConditionalCheckFailedException e) {
LOGGER.info("Skipped saving as not unique...");
}
}
此代码将一遍又一遍地保存 Server 对象,而不会引发异常.
This code will save the Server object over and over again with the exception never being thrown.
服务器 POJO
@DynamoDBTable(tableName = "Servers")
public class Server {
@Id
private String id = UUID.randomUUID().toString();
@DynamoDBTypeConvertedJson
private Task task;
@DynamoDBAttribute(attributeName = "instanceId")
private String instanceId;
public Server() {
}
@DynamoDBHashKey
public String getId() {
return id;
}
// other standard getters and setters
}
推荐答案
2019更新
在 2019 年,自提出问题以来,这里似乎没有任何变化.在 DynamoDB 中为非主键字段提供唯一性仍然很棘手.这是最近在亚马逊上发布的一篇文章:https://aws.amazon.com/blogs/database/simulating-amazon-dynamodb-unique-constraints-using-transactions/
基本上,作者建议在同一个表中创建辅助记录,而不是使用如下所述的附加表.
Basically, instead of using an additional table as described below, the author proposes creating auxiliary records in the same table.
例如,在下图中,为确保 instance_id=2c5d0cc8d900 是唯一值,您必须添加具有人工主键值instance_id#2c5d0cc8d900"的记录.如果插入成功,您可以插入主记录本身.
For example, on the below picture, for ensuring that instance_id=2c5d0cc8d900 is a unique value, you have to add a record with an artificial primary key value "instance_id#2c5d0cc8d900". If the insert succeeds, you can insert the main record itself.
+--------------------------+-------------------------+--------+----------------
| id | instance_id | attr1 | other fields...
| | | |
| (primary key) | (a non-key field, | |
| | must be unique) | |
+--------------------------+-------------------------+--------+----------------
| instance_id#2c5d0cc8d900 | | |
| a9fd702a | 2c5d0cc8d900 | qwerty | ...
虽然这种方法可能效果很好,但我个人仍然更喜欢使用单独的表格,如下面的原始答案所述.因为,当从包含此类辅助记录的表中读取数据时,您必须注意从实际记录中过滤它们.
While this approach may work fine, I personally still prefer to use a separate table like described below in my original answer. Because, when reading data from a table that contains such auxiliary records, you have to care about filtering them from actual ones.
如果我正确理解了这个问题,您希望确保不是哈希键的字段的唯一性.
If I correctly understood the question, you'd like to ensure uniqueness for a field which is not the hash key.
(我不知道你为什么不使用 instanceId
作为 Servers 表的哈希键,我猜你是有原因的).
(I'm not sure why you do not use instanceId
as the hash key for Servers table, I guess you have a reason for that).
我的回答:看起来如果不使用辅助表就无法做到这一点.
这是您现有的服务器表:
Here is your existing Servers table:
+----------------------------------------------+
| Servers |
+----------------------------------------------+
| * id the hash key |
| * instanceId non-key field, must be unique|
| |
| * ... |
| * other fields |
| * ... |
+----------------------------------------------+
我会创建一个带有 instanceId 作为哈希键的附加表:
I would create an additional table with instanceId as the hash key:
+----------------------------------------------+
| Instance |
+----------------------------------------------+
| * instanceId the hash key |
+----------------------------------------------+
有了这样的表,在将记录保存到服务器之前,您必须首先确保 instanceId 值是唯一的,方法是向 Instance 添加一条记录 (putItem),提供类似 attribute_not_exists(instanceId)
的 ConditionExpression.
Having such a table, before saving a record into Servers, you have to
ensure first that instanceId value is unique by adding a record (putItem) into Instance, providing a ConditionExpression like attribute_not_exists(instanceId)
.
只有当 put 操作完成且没有出现 ConditionalCheckFailedException
错误时,您才能继续将记录添加到服务器中.
And only if the put operation completes without an ConditionalCheckFailedException
error, you can proceed with adding the record into Servers.
如果您想根据 instanceId 和 imageId 这两个字段的组合来确保服务器中记录的唯一性,而不是 instanceId 使用这些字段的连接值作为辅助表中的单个字段:
If you'd like to ensure uniqueness of records in Servers based on combination of two fields, instanceId and imageId, instead of just instanceId use concatenated values of these fields as a single field in your aux table:
+----------------------------------------------+
| Instance_Image |
+----------------------------------------------+
| * instanceId_imageId the hash key |
+----------------------------------------------+
相关文章