在我的数据库方案中,我需要一个自动增量主键。我如何实现这个功能?
提示:为了访问DynamoDB, 我使用了Node.js的模块dynode。
在我的数据库方案中,我需要一个自动增量主键。我如何实现这个功能?
提示:为了访问DynamoDB, 我使用了Node.js的模块dynode。
免责声明:我是Dynamodb-mapper项目的维护者。
自增键的直观工作流程:
这只是为了解释基本思路。永远不要这样做,因为这不是原子操作。在某些工作负载下,由于它不是原子操作,您可能会将相同的ID分配给2个或更多不同的对象,从而导致数据丢失。
解决方案是使用UpdateItem的原子ADD操作和ALL_NEW :
在最坏的情况下,应用程序在对象保存之前崩溃,但永远不会有重复分配ID的风险。
还有一个问题:要存储上次的ID值在哪里?我们选择:
{
"hash_key"=-1, #0 was judged too risky as it is the default value for integers.
"__max_hash_key__y"=N
}
当然,为了能够可靠地工作,所有插入数据的应用程序都必须知道该系统,否则您可能会(再次)覆盖数据。
最后一步是自动化该过程。例如:
When hash_key is 0:
atomically_allocate_ID()
actual_save()
有关实现细节(使用Python,抱歉)请参见https://bitbucket.org/Ludia/dynamodb-mapper/src/8173d0e8b55d/dynamodb_mapper/model.py#cl-67
说实话,我的公司没有在生产中使用它,因为大多数情况下最好找到另一个关键词,例如对于用户,ID,对于交易,日期时间...
我在dynamodb-mapper的文档中编写了一些示例,并且可以轻松地推广到Node.JS
如果您有任何问题,请随时提出。
另一种方法是使用UUID
生成器作为主键,因为这些几乎不可能发生冲突。
在我看来,跨高可用性的DynamoDB
表合并主键计数器时出现错误的可能性比生成的UUID
冲突要大。
例如,在Node中:
npm install uuid
var uuid = require('uuid');
// Generate a v1 (time-based) id
uuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'
// Generate a v4 (random) id
uuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'
来自SO的答案。
var conditionalPutParams = {
TableName: 'NextIdTable',
Item: {
Counter: {
N: '39'
}
},
Expected: {
Counter: {
AttributeValueList: [
{
N: '38'
}
],
ComparisonOperator: 'EQ'
}
}
};
像这样使用DynamoDBAutoGeneratedKey注释。DynamoDBAutoGeneratedKey
将分区键或排序键属性标记为自动生成。 DynamoDBMapper将在保存这些属性时生成随机UUID。只有字符串属性才能标记为自动生成的键。
@DynamoDBTable(tableName="AutoGeneratedKeysExample")
public class AutoGeneratedKeys {
private String id;
@DynamoDBHashKey(attributeName = "Id")
@DynamoDBAutoGeneratedKey
public String getId() { return id; }
public void setId(String id) { this.id = id; }
如上例所示,您可以在同一属性上应用DynamoDBAutoGeneratedKey和DynamoDBHashKey注释,以生成唯一的哈希键。
AWS支持原子计数器。
创建一个单独的表格(order_id
),其中包含一行,保存最新的订单号:
+----+--------------+
| id | order_number |
+----+--------------+
| 0 | 5000 |
+----+--------------+
1
config={
region: 'us-east-1',
endpoint: "http://localhost:8000"
};
const docClient = new AWS.DynamoDB.DocumentClient(config);
let param = {
TableName: 'order_id',
Key: {
"id": 0
},
UpdateExpression: "set order_number = order_number + :val",
ExpressionAttributeValues:{
":val": 1
},
ReturnValues: "UPDATED_NEW"
};
docClient.update(params, function(err, data) {
if (err) {
console.log("Unable to update the table. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log(data);
console.log(data.Attributes.order_number); // <= here is our incremented result
}
});
从性能角度来看,自动递增不是很好,因为它会使某些分片过载而保持其他分片空闲,如果您要存储数据到DynamoDB中,它并不能实现均匀分布。
awsRequestId
看起来实际上是V.4 UUID(随机生成),以下是代码片段:
import uuid
print(str(uuid.uuid4()))
请注意:本文仅供参考,具体实现可能会有所不同。
exports.handler = function(event, context, callback) {
console.log('remaining time =', context.getRemainingTimeInMillis());
console.log('functionName =', context.functionName);
console.log('AWSrequestID =', context.awsRequestId);
callback(null, context.functionName);
};
对于Go开发人员,您可以使用这些来自Google's UUID、Pborman或Satori的包。Pborman在性能方面更好,查看这些文章和基准测试以获取更多详细信息。
有关通用唯一标识符规范的更多信息,请单击此处。
const dynamoose = require("dynamoose");
const userSchema = new dynamoose.Schema(
{
id: {
type: String,
hashKey: true,
},
displayName: String,
firstName: String,
lastName: String,
},
{ timestamps: true },
);
const User = dynamoose.model("User", userSchema);
module.exports = User;
// 用户控制器.js
const { v4: uuidv4 } = require("uuid");
const User = require("./user.model");
exports.create = async (req, res) => {
const user = new User({ id: uuidv4(), ...req.body }); // set unique id
const [err, response] = await to(user.save());
if (err) {
return badRes(res, err);
}
return goodRes(res, reponse);
};