DynamoDB — DynamoDbAtomicCounter всегда возвращает значение null

Я следую этому документу:

https://aws.amazon.com/blogs/developer/using-atomic-counters-in-the-enhanced-dynamodb-aws-sdk-for-java-2-x-client/

Моя цель — использовать AtomicCounter для генерации уникальных идентификаторов, но я всегда получаю null для обоих примеров:

Мой код выглядит так:

@DynamoDbBean
public class CustomerDocument {

    private String root;
    private Long updateCounter;
    private Long customCounter;

    @DynamoDbPartitionKey
    public String getRoot() {
        return this.root;
    }

    public void setRoot(String id) {
        this.root = id;
    }

    @DynamoDbAtomicCounter
    public Long getUpdateCounter() {
        return this.updateCounter;
    }

    public void setUpdateCounter(Long counter) {
        this.updateCounter = counter;
    }

    @DynamoDbAtomicCounter(delta = 5, startValue = 10)
    public Long getCustomCounter() {
        return this.customCounter;
    }

    public void setCustomCounter(Long counter) {
        this.customCounter = counter;
    }
}

хранилище

CustomerDocument document = new CustomerDocument();
document.setRoot(root);

customerTable.updateItem(document);
CustomerDocument retrievedCustomer = customerTable.getItem(document);

retrievedCustomer.getUpdateCounter(); // null
retrievedCustomer.getCustomCounter(); // null

customerTable.updateItem(document);

retrievedCustomer = orderCounterTable.getItem(document);
retrievedCustomer.getUpdateCounter(); // null
retrievedCustomer.getCustomCounter(); // null

Любая идея о проблеме, пожалуйста?


Редактировать

на основе ответа выше мой код теперь выглядит так:

public CustomerDocument nextCounter(String root) {
    CustomerDocument document = new CustomerDocument();
    document.setId(root);
    CustomerDocument item = orderCounterTable.getItem(document);
    if (item == null) {
        CustomerDocument defaultDocument = new CustomerDocument();
        defaultDocument.setId(root);
        defaultDocument.setCount(1L);
        customerTable.putItem(defaultDocument);
        return defaultDocument;
    } else {
        CustomerDocument newDocument = new CustomerDocument();
        newDocument.setId(item.getId());
        return customerTable.updateItem(newDocument);
    }
}

Но я все равно получаю null каждый orderCounterTable.updateItem(newDocument):

Я получаю только:

{
    "id": "20042024"
}
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
85
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Эта функция работает так, как показано в примере бессерверного приложения для управления фоторесурсами, в котором используется DynamoDbAtomicCounter.

В этом примере внешний интерфейс — это приложение React. Серверная часть использует AWS SDK для Java V2. Каждый раз, когда приложение находит новую метку с помощью Amazon Rekognition, столбец счетчика в таблице Amazon DynamoDB увеличивается с помощью DynamoDbAtomicCounter. Вот пользовательский интерфейс React. Вы можете увидеть количество для каждой метки.

Вот применимый код, который заставляет его работать.

Это класс DynamoDB, который использует необходимые аннотации, такие как @DynamoDbAtomicCounter.

    package com.example.photo;
    
    import software.amazon.awssdk.enhanced.dynamodb.extensions.annotations.DynamoDbAtomicCounter;
    import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
    import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
    import java.util.List;
    
    @DynamoDbBean
    public class Label {
        private String id;
        private Integer count;
        private List<String> images;
    
        @DynamoDbPartitionKey
        public String getId() {
            return this.id;
        };
        public void setId(String id) {
            this.id = id;
        }
    
        @DynamoDbAtomicCounter (startValue = 1)
        public Integer getCount() {
            return this.count;
        }
        public void setCount(Integer count) {
            this.count = count;
        }
    
        public List<String> getImages() {
            return this.images;
        }
        public void setImages(List<String> images) {
            this.images = images;
        }
    }

Вот метод, где он используется с Enhanced Client:

private void addSingleRecord(DynamoDbTable<Label> table, String tag, String key) {
        // Check to see if the label exists in the Amazon DynamoDB table.
        // The count item uses an @DynamoDbAtomicCounter which means it is
        // updated automatically. No need to manually set this value when the record is
        // created or updated.
        if (!checkTagExists(table, tag)) {
            Label photoRec = new Label();
            photoRec.setId(tag);
            List<String> keyList = new ArrayList<>();
            keyList.add(key);
            photoRec.setImages(keyList);
            table.putItem(photoRec);
        } else {
            // The tag exists in the table.
            Key myKey = Key.builder()
                .partitionValue(tag)
                .build();

            // Add the file name to the list.
            Label myPhoto = table.getItem(myKey);
            Label updatedPhoto = new Label();
            List<String> imageList = myPhoto.getImages();
            imageList.add(key);
            updatedPhoto.setId(tag);
            updatedPhoto.setImages(imageList);
            table.updateItem(updatedPhoto);
        }
    }

ОБНОВЛЯТЬ

Обратите внимание, что здесь есть хитрость — от команды SDK:

«Я понял, что происходит. Это потому, что мы повторно используем тот же объект, который мы читаем из базы данных с помощью «getItem». Если вы создаете новый объект и устанавливаете данные, он работает».

Это может быть причиной вашей проблемы. Создайте новый объект, установите данные, и произойдет приращение. Обратите внимание, что здесь я создаю новый объект:

Label updatedPhoto = new Label();
 List<String> imageList = myPhoto.getImages();
 imageList.add(key);
 updatedPhoto.setId(tag);
 updatedPhoto.setImages(imageList);
 table.updateItem(updatedPhoto);

Вы можете найти этот полный пример в Библиотеке кода AWS. Вы можете закодировать серверную часть и использовать AWS CDK для установки ресурсов и запуска этого приложения. Следуйте указаниям в документе и следуйте инструкциям CDK. После того, как вы выполните все, вы увидите приложение в действии и работающий DynamoDbAtomicCounter.

Видеть:

Создайте приложение для управления фоторесурсами, которое позволит пользователям управлять фотографиями с помощью ярлыков

ОБНОВЛЕНИЕ ВАШЕГО КОДА

Мне пришлось внести несколько изменений в ваш код.

КОД:

EnhancedAtomicCounter

  package com.example.dynamodb.enhanced.test;

import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.Key;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;

public class EnhancedAtomicCounter {

    public static void main(String[] args) {
        ProfileCredentialsProvider credentialsProvider = ProfileCredentialsProvider.create();
        Region region = Region.US_EAST_1;
        DynamoDbClient ddb = DynamoDbClient.builder()
            .credentialsProvider(EnvironmentVariableCredentialsProvider.create())
            .region(region)
            .build();

        DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
            .dynamoDbClient(ddb)
            .build();

        String root = "1000";
        putCustObj(enhancedClient, root);
        updateRec(enhancedClient, root);
        updateRec2(enhancedClient, root);

    }

    public static void putCustObj(DynamoDbEnhancedClient enhancedClient, String root) {
        DynamoDbTable<CustomerDocument> mappedTable = enhancedClient.table("CustomerDocument", TableSchema.fromBean(CustomerDocument.class));
        CustomerDocument document = new CustomerDocument();
        document.setRoot(root);
        document.setName("Scott");
        document.setCustomCounter(200L);

        // Put the customer data into an Amazon DynamoDB table.
        mappedTable.putItem(document);
    }

    public static void updateRec(DynamoDbEnhancedClient enhancedClient, String root) {
        DynamoDbTable<CustomerDocument> mappedTable = enhancedClient.table("CustomerDocument", TableSchema.fromBean(CustomerDocument.class));
        Key key = Key.builder()
            .partitionValue(root)
            .build();

        // Get the item by using the key.
        CustomerDocument result = mappedTable.getItem(r->r.key(key));

        // Create a new object so  @DynamoDbAtomicCounter works
        CustomerDocument newCustOb = new CustomerDocument();
        newCustOb.setRoot(result.getRoot());
        newCustOb.setName("Scott2");
        mappedTable.updateItem(newCustOb);
    }

    public static void updateRec2(DynamoDbEnhancedClient enhancedClient, String root) {
        DynamoDbTable<CustomerDocument> mappedTable = enhancedClient.table("CustomerDocument", TableSchema.fromBean(CustomerDocument.class));
        Key key = Key.builder()
            .partitionValue(root)
            .build();

        // Get the item by using the key.
        CustomerDocument result = mappedTable.getItem(r->r.key(key));

        // Create a new object so  @DynamoDbAtomicCounter works
        CustomerDocument newCustOb = new CustomerDocument();
        newCustOb.setRoot(result.getRoot());
        newCustOb.setName("Scott3");
        mappedTable.updateItem(newCustOb);
        System.out.println("Item updated!");
    }
}

КлиентДокумент

package com.example.dynamodb.enhanced.test;

import software.amazon.awssdk.enhanced.dynamodb.extensions.annotations.DynamoDbAtomicCounter;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;

@DynamoDbBean
public class CustomerDocument {

    private String root;
    private String name;
    private Long updateCounter;
    private Long customCounter;

    @DynamoDbPartitionKey
    public String getRoot() {
        return this.root;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setRoot(String id) {
        this.root = id;
    }

    @DynamoDbAtomicCounter (startValue = 1)
    public Long getUpdateCounter() {
        return this.updateCounter;
    }

    public void setUpdateCounter(Long counter) {
        this.updateCounter = counter;
    }

    @DynamoDbAtomicCounter(delta = 5, startValue = 10)
    public Long getCustomCounter() {
        return this.customCounter;
    }

    public void setCustomCounter(Long counter) {
        this.customCounter = counter;
    }
}

В моем примере я сделал несколько обновлений записи, изменив имя. Сейчас
updateCounter должно быть 3. Это:

Эй, спасибо за ваш ответ, я использовал ту же логику, и я все еще получаю нуль для счетчика, я не понимаю, что вы подразумеваете под This functionality works fine as long as you setup the code correctly что не так с моим кодом !?

Doesn't Matter 27.04.2023 18:06

Смотрите мое обновление здесь. ОТ команды SDK: «Я понял, что происходит. Это потому, что мы повторно используем тот же объект, который мы считываем из базы данных с помощью «getItem». Если вы создаете новый объект и устанавливаете данные, он работает». См. этикетку updatedPhoto. это новый объект, который я использую для обновления таблицы.

smac2020 27.04.2023 18:09

спасибо за ваш ответ, я использовал тот же трюк, но я все еще получаю нуль для счетчика, вы можете проверить мой новый код в моем ответе, пожалуйста.

Doesn't Matter 27.04.2023 18:22

Я могу понять схему вашего стола. Я попытаюсь воспроизвести вашу таблицу и ваш код. Я хочу посмотреть, смогу ли я воспроизвести вашу проблему

smac2020 27.04.2023 18:45

Я опубликую свои выводы.

smac2020 27.04.2023 18:49

Я сделал несколько модификаций вашего кода, и теперь он отлично работает. 2 элемента с @DynamoDbAtomicCounter обновляются, как показано на моем снимке экрана.

smac2020 27.04.2023 20:26

Я понял, почему мое решение не работает :), пожалуйста, проверьте мой ответ здесь

Doesn't Matter 28.04.2023 09:58

Сравнивая свой код и код @smac2020, я понимаю, что использую .extensions(VersionedRecordExtension.builder().build()):

DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
        .dynamoDbClient(amazonDynamoDB())
    --> //.extensions(VersionedRecordExtension.builder().build())
        .build();

Удалив эту конфигурацию, мое решение работает нормально.

мой окончательный код был просто:

public CustomerDocument nextCounter(String root) {
    CustomerDocument newDocument = new CustomerDocument();
    newDocument.setRoot(root);
    return customerTable.updateItem(newDocument);
}

Ни putItem, ничего другого.

Рад, что это работает

smac2020 28.04.2023 14:36

Другие вопросы по теме