확장 프로그램을 사용하여 DynamoDB 향상된 클라이언트 작업 사용자 지정
DynamoDB 향상된 클라이언트 API는 매핑 작업 이외의 기능을 제공하는 플러그인 확장을 지원합니다. 확장 프로그램은 2가지 후크 메서드를 사용하여 읽기 및 쓰기 작업 중에 데이터를 수정합니다.
beforeWrite()- 쓰기 작업이 발생하기 전에 수정합니다.afterRead()- 읽기 작업이 발생한 후 결과를 수정합니다.
일부 작업(예: 항목 업데이트)은 쓰기와 읽기를 차례로 모두 수행하므로 두 후크 메서드가 모두 호출됩니다.
확장 프로그램 로드 방법
확장 프로그램은 향상된 클라이언트 빌더에 지정된 순서대로 로드됩니다. 하나의 확장이 이전 확장에 의해 변환된 값에 대해 작동할 수 있으므로 로드 순서가 중요할 수 있습니다.
기본적으로 향상된 클라이언트는 2개의 확장 프로그램을 로드합니다.
VersionedRecordExtension- 낙관적 잠금 제공AtomicCounterExtension- 카운터 속성을 자동으로 증분
향상된 클라이언트 빌더로 기본 동작을 재정의하고 모든 확장 프로그램을 로드할 수 있습니다. 기본 확장자를 원하지 않는 경우에는 none을 지정할 수도 있습니다.
중요
자체 확장을 로드하는 경우 확장 클라이언트는 기본 확장을 로드하지 않습니다. 기본 확장 중 하나가 제공하는 동작을 원하는 경우 해당 확장을 확장 목록에 명시적으로 추가해야 합니다.
다음 예제에서는 VersionedRecordExtension 이후 이름이 verifyChecksumExtension인 사용자 지정 확장 프로그램을 로드하는 방법을 보여줍니다. 이 예제에서는 AtomicCounterExtension가 로드되지 않습니다.
DynamoDbEnhancedClientExtension versionedRecordExtension = VersionedRecordExtension.builder().build(); DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder() .dynamoDbClient(dynamoDbClient) .extensions(versionedRecordExtension, verifyChecksumExtension) .build();
사용 가능한 확장 프로그램 세부 정보 및 구성
다음 섹션에서는 SDK에서 사용 가능한 각 확장 프로그램에 대한 자세한 정보를 제공합니다.
VersionedRecordExtension을 사용한 낙관적 잠금 구현
VersionedRecordExtension 확장 프로그램은 항목이 데이터베이스에 작성될 때 항목 버전 번호를 증분하고 추적하여 낙관적 잠금을 제공합니다. 실제 지속 항목의 버전 번호가 애플리케이션이 마지막으로 읽은 값과 일치하지 않는 경우 쓰기가 실패하도록 하는 조건이 모든 쓰기에 추가됩니다.
구성
항목 버전 번호를 추적하는 데 사용할 속성을 지정하려면 테이블 스키마에서 숫자 속성에 태그를 지정하세요.
다음 코드 조각은 version 속성에 항목 버전 번호가 포함되도록 지정합니다.
@DynamoDbVersionAttribute public Integer getVersion() {...}; public void setVersion(Integer version) {...};
동일한 정적 테이블 스키마 접근 방식이 다음 코드 조각에 나와 있습니다.
.addAttribute(Integer.class, a -> a.name("version") .getter(Customer::getVersion) .setter(Customer::setVersion) // Apply the 'version' tag to the attribute. .tags(VersionedRecordExtension.AttributeTags.versionAttribute())
작동 방법
VersionedRecordExtension이 있는 낙관적 잠금 전략은 이러한 DynamoDbEnhancedClient 및 DynamoDbTable 메서드에 다음과 같은 영향을 끼칩니다.
putItem-
새 항목에는 초기 버전 값 0이 할당됩니다.
@DynamoDbVersionAttribute(startAt =로 구성할 수 있습니다.X) updateItem-
이후 항목을 검색하여 속성을 하나 이상 업데이트한 후 변경 사항을 저장하려고 해도 클라이언트 측과 서버 측의 버전 번호가 일치해야만 작업이 완료됩니다.
작업이 완료되면 버전 번호가 자동으로 1씩 증분됩니다.
@DynamoDbVersionAttribute(incrementBy =로 구성할 수 있습니다.X) deleteItem-
DynamoDbVersionAttribute주석은 영향을 미치지 않습니다. 항목을 삭제할 때 조건 표현식을 수동으로 추가해야 합니다.다음 예제에서는 조건식을 추가하여 삭제된 항목이 읽은 항목인지 확인합니다. 다음 예제(
recordVersion)에서는@DynamoDbVersionAttribute주석이 달린 bean의 속성입니다.// 1. Read the item and get its current version. Customer item = customerTable.getItem(Key.builder().partitionValue("someId").build()); // `recordVersion` is the bean's attribute that is annotated with `@DynamoDbVersionAttribute`. AttributeValue currentVersion = item.getRecordVersion(); // 2. Create conditional delete with the `currentVersion` value. DeleteItemEnhancedRequest deleteItemRequest = DeleteItemEnhancedRequest.builder() .key(KEY) .conditionExpression(Expression.builder() .expression("recordVersion = :current_version_value") .putExpressionValue(":current_version_value", currentVersion) .build()).build(); customerTable.deleteItem(deleteItemRequest); transactWriteItems-
-
addPutItem: 이 메서드는putItem과 동일한 동작을 갖습니다. -
addUpdateItem: 이 메서드는updateItem과 동일한 동작을 갖습니다. -
addDeleteItem: 이 메서드는deleteItem과 동일한 동작을 갖습니다.
-
batchWriteItem-
-
addPutItem: 이 메서드는putItem과 동일한 동작을 갖습니다. -
addDeleteItem: 이 메서드는deleteItem과 동일한 동작을 갖습니다.
-
참고
DynamoDB 전역 테이블은 동시 업데이트 간에 ‘최종 라이터 우선 적용’ 조정을 사용하며, DynamoDB는 최종 라이터를 확인하기 위해 노력합니다. 전역 테이블을 사용하는 경우 이 '최종 라이터 우선 적용' 정책은 모든 복제본이 결국 DynamoDB에서 결정한 최종 쓰기를 기반으로 수렴되므로 잠금 전략이 예상대로 작동하지 않을 수 있음을 의미합니다.
사용 해제 방법
낙관적 잠금을 사용 해제하려면 @DynamoDbVersionAttribute 주석을 사용하지 않습니다.
AtomicCounterExtension을 사용하여 카운터 구현
AtomicCounterExtension 확장 프로그램은 레코드가 데이터베이스에 기록될 때마다 태그가 지정된 숫자 속성을 증분시킵니다. 시작 및 증분 값을 지정할 수 있습니다. 값을 지정하지 않으면 시작 값은 0으로 설정되고 속성 값은 1씩 증가합니다.
구성
어떤 속성이 카운터인지 지정하려면 테이블 스키마에서 Long 유형의 속성에 태그를 지정하세요.
다음 코드 조각은 counter 속성의 기본 시작 및 증분 값 사용을 보여줍니다.
@DynamoDbAtomicCounter public Long getCounter() {...}; public void setCounter(Long counter) {...};
정적 테이블 스키마 접근 방식이 다음 코드 조각에 나와 있습니다. 원자 카운터 확장은 시작 값 10을 사용하고 레코드가 기록될 때마다 값을 5씩 증가시킵니다.
.addAttribute(Integer.class, a -> a.name("counter") .getter(Customer::getCounter) .setter(Customer::setCounter) // Apply the 'atomicCounter' tag to the attribute with start and increment values. .tags(StaticAttributeTags.atomicCounter(10L, 5L))
AutoGeneratedTimestampRecordExtension을 사용하여 타임스탬프 추가
AutoGeneratedTimestampRecordExtension 확장 프로그램은 항목이 데이터베이스에 성공적으로 기록될 때마다 Instant 유형의 태그가 지정된 속성을 현재 타임스탬프로 자동 업데이트합니다. 이 확장은 기본적으로 로드되지 않습니다.
구성
현재 타임스탬프로 업데이트할 속성을 지정하려면 테이블 스키마에서 Instant 속성에 태그를 지정하세요.
lastUpdate 속성은 다음 코드 조각에서 확장 프로그램의 동작 대상입니다. 속성이 Instant 유형이어야 한다는 요구 사항에 유의하세요.
@DynamoDbAutoGeneratedTimestampAttribute public Instant getLastUpdate() {...} public void setLastUpdate(Instant lastUpdate) {...}
동일한 정적 테이블 스키마 접근 방식이 다음 코드 조각에 나와 있습니다.
.addAttribute(Instant.class, a -> a.name("lastUpdate") .getter(Customer::getLastUpdate) .setter(Customer::setLastUpdate) // Applying the 'autoGeneratedTimestamp' tag to the attribute. .tags(AutoGeneratedTimestampRecordExtension.AttributeTags.autoGeneratedTimestampAttribute())
AutoGeneratedUuidExtension을 사용하여 UUID 생성
AutoGeneratedUuidExtension 확장 프로그램은 새 레코드가 데이터베이스에 기록될 때 속성에 대한 고유한 UUID(범용 고유 식별자)를 생성합니다. Java JDK UUID.randomUUID()java.lang.String 유형의 속성에 적용됩니다. 이 확장은 기본적으로 로드되지 않습니다.
구성
uniqueId 속성은 다음 코드 조각에서 확장 프로그램의 동작 대상입니다.
@AutoGeneratedUuidExtension public String getUniqueId() {...} public void setUniqueId(String uniqueId) {...}
동일한 정적 테이블 스키마 접근 방식이 다음 코드 조각에 나와 있습니다.
.addAttribute(String.class, a -> a.name("uniqueId") .getter(Customer::getUniqueId) .setter(Customer::setUniqueId) // Applying the 'autoGeneratedUuid' tag to the attribute. .tags(AutoGeneratedUuidExtension.AttributeTags.autoGeneratedUuidAttribute())
확장 프로그램이 putItem 메서드에 한해 UUID를 채우고 updateItem 메서드에는 채우지 않도록 하려면 다음 코드 조각과 같이 업데이트 동작
@AutoGeneratedUuidExtension @DynamoDbUpdateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS) public String getUniqueId() {...} public void setUniqueId(String uniqueId) {...}
정적 테이블 스키마 접근 방식을 사용하는 경우 다음과 같은 동등한 코드를 사용합니다.
.addAttribute(String.class, a -> a.name("uniqueId") .getter(Customer::getUniqueId) .setter(Customer::setUniqueId) // Applying the 'autoGeneratedUuid' tag to the attribute. .tags(AutoGeneratedUuidExtension.AttributeTags.autoGeneratedUuidAttribute(), StaticAttributeTags.updateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS))