В моей схеме db мне нужен первичный ключ автоинкремента. Как я могу реализовать эту функцию?
PS Для доступа к DynamoDB я использую dynode, модуль для Node.js.
В моей схеме db мне нужен первичный ключ автоинкремента. Как я могу реализовать эту функцию?
PS Для доступа к DynamoDB я использую dynode, модуль для Node.js.
Отказ от ответственности: я являюсь разработчиком проекта Dynamodb-mapper
Интуитивно понятный рабочий процесс ключа автоматического инкремента:
Это просто объяснение основной идеи. Никогда не делайте этого так, потому что это не атомный. При определенной рабочей нагрузке вы можете назначить один и тот же идентификатор двум другим объектам, потому что они не являются атомарными. Это приведет к потере данных.
Решение состоит в использовании операции атомной ADD и ALL_NEW UpdateItem:
В худшем случае приложение аварийно завершает работу до того, как объект будет сохранен, но никогда не рискует дважды назначить один и тот же идентификатор.
Остается одна проблема: где сохранить последнее значение идентификатора? Мы выбрали:
{
"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
По правде говоря, моя компания не использует его в производстве, потому что большую часть времени лучше найти другой ключ, например, для пользователя, идентификатор для транзакции, дату-время,...
Я написал несколько примеров в документации dynamodb-mapper и его можно легко экстраполировать на Node.JS
Если у вас есть какие-либо вопросы, не стесняйтесь спрашивать.
Если у вас все в порядке с пробелами в увеличивающемся идентификаторе, и вы в порядке с ним, только приблизительно соответствующим порядку, в котором были добавлены строки, вы можете свернуть свою собственную: создайте отдельную таблицу с именем NextIdTable с одним первичным ключом ( числовой), назовите его Counter.
Каждый раз, когда вы хотите сгенерировать новый идентификатор, вы должны сделать следующее:
Конечно, если ваш процесс завершится сбоем до фактического применения этого идентификатора в любом месте, вы "утечете" его и в вашей последовательности идентификаторов будет пробел. И если вы делаете это одновременно с каким-то другим процессом, один из вас получит значение 39, а другой - 40, и нет никаких гарантий относительно того, в каком порядке они будут фактически применяться в вашей таблице данных; парень, получивший 40, мог бы написать это раньше, чем парень, получивший 39. Но это дает вам грубый порядок.
Параметры условного PutItem в node.js подробно описаны здесь. http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/frames.html#!AWS/DynamoDB.html. Если вы ранее прочитали значение 38 из Counter, ваш условный запрос PutItem может выглядеть следующим образом.
var conditionalPutParams = {
TableName: 'NextIdTable',
Item: {
Counter: {
N: '39'
}
},
Expected: {
Counter: {
AttributeValueList: [
{
N: '38'
}
],
ComparisonOperator: 'EQ'
}
}
};
Другим подходом является использование генератора UUID
для первичных ключей, поскольку они вряд ли могут столкнуться.
IMO, вы с большей вероятностью столкнетесь с ошибками, консолидирующими счетчики первичных ключей в высокодоступных таблицах DynamoDB
, чем из столкновений в сгенерированных UUID
s.
Например, в 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 answer.
Я не верю, что это возможно для автоматического приращения стиля SQL, потому что таблицы разбиты на несколько машин. Я создаю свой собственный UUID в PHP, который выполняет эту работу, я уверен, что вы могли бы придумать что-то подобное как это в javascript.
Дополнение к ответу @yadutaf
AWS поддерживает атомные счетчики.
Создайте отдельную таблицу (order_id
) со строкой, содержащей последний номер order_number:
+----+--------------+
| id | order_number |
+----+--------------+
| 0 | 5000 |
+----+--------------+
Это позволит увеличить order_number на 1
и получить увеличенный результат в обратном вызове из AWS DynamoDB:
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
}
});
🛈 Имейте в виду, что в некоторых редких случаях могут возникнуть проблемы с соединением между точкой вызова и API AWS. Это приведет к увеличению строки динамодб, в то время как вы получите ошибку соединения. Таким образом, могут появиться некоторые неиспользованные увеличенные значения.
Вы можете использовать увеличенные data.Attributes.order_number
в своей таблице, например, чтобы вставить {id: data.Attributes.order_number, otherfields:{}}
в таблицу order
.
Для этих кодировок в Java DynamoDBMapper теперь может генерировать уникальные UUID от вашего имени.
DynamoDBAutoGeneratedKey
Помечает ключ раздела или свойство ключа сортировки как автоматически сгенерированный. DynamoDBMapper генерирует случайный UUID при сохранении этих атрибутов. Только свойства String могут быть помечены как автоматически сгенерированные ключи.
Используйте комментарий DynamoDBAutoGeneratedKey, подобный этому
@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 к тому же атрибуту для генерации уникального хеш-ключа.
У меня была такая же проблема, и я создал небольшую веб-службу именно для этой цели. См. Это сообщение в блоге, в котором объясняется, как я использую stateful.co с DynamoDB, чтобы имитировать функции автоматического увеличения: http://www.yegor256.com/2014/05/18/cloud-autoincrement-counters.html
В принципе, вы регистрируете атомный счетчик в stateful.co и увеличиваете его каждый раз, когда вам нужно новое значение, через RESTful API. Услуга бесплатна.
Создайте новый file.js
и поместите этот код:
exports.guid = function () {
function _p8(s) {
var p = (Math.random().toString(16)+"000000000").substr(2,8);
return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
}
return (_p8() + _p8(true) + _p8(true)+new Date().toISOString().slice(0,10)).replace(/-/g,"");
}
Затем вы можете применить эту функцию к идентификатору первичного ключа. Он будет генерировать UUID.
Используя схему AWS dynamodb data mapper в Node.js, хеш-ключ (id) будет сгенерирован автоматически. Автогенерируемые идентификаторы основаны на uuid v4.
Подробнее см. следующий пакет aws.
Пакет Data Mapper для Javascript
Пример снайпера
@table('my_table')
class MyDomainClass {
@autoGeneratedHashKey()
id: string;
@rangeKey({defaultProvider: () => new Date()})
createdAt: Date;
}
Автоинкремент не очень хорош с точки зрения производительности, поскольку он перегружает отдельные фрагменты, в то время как другие не работают. Он не обеспечивает равномерного распределения, если вы храните данные в Dynamodb.
awsRequestId
выглядит как его V.4 UUID (Random), фрагмент кода ниже, чтобы попробовать это:
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);
};
Если вы хотите сгенерировать это самостоятельно, вы можете использовать https://www.npmjs.com/package/uuid или Ulide для генерации различных версий UUID на основе RFC-4122.
Для разработчиков Go вы можете использовать эти пакеты от Google UUID, Pborman или Satori. Pborman лучше работает, проверьте эти статьи и тесты для получения более подробной информации.
Более подробную информацию о спецификации универсального уникального идентификатора можно найти здесь.