DynamoDB 및 버전 번호를 이용한 낙관적 잠금
낙관적 잠금은 업데이트 또는 삭제하려는 클라이언트 측 항목이 Amazon DynamoDB의 항목과 동일하도록 하려는 전략입니다. 이 전략을 사용하면 다른 사용자의 쓰기 작업이 자신의 데이터베이스 쓰기 작업을 덮어쓰지 못하도록 보호하며, 그 반대도 마찬가지입니다.
낙관적 잠금 전략에서는 각 항목마다 버전 번호 역할을 하는 속성이 있습니다. 항목을 테이블에서 가져오면 애플리케이션이 해당 항목의 버전 번호를 기록합니다. 이 항목을 업데이트할 수는 있지만 서버 쪽 버전 번호가 바뀌지 않는 경우에 한합니다. 버전 불일치가 있는 경우 사용자가 항목을 수정하기 전에 다른 사람이 해당 항목을 수정했음을 의미합니다. 더 이상 유효하지 않은 항목 버전이 있으므로 업데이트 시도가 실패합니다. 이러한 경우 항목을 검색한 후 해당 항목 업데이트를 시도하여 재시도합니다. 낙관적 잠금을 통해 다른 사람이 수행한 변경 사항을 잘못 덮어쓰지 않게 됩니다. 또한 다른 사람이 사용자의 변경 사항을 잘못 덮어쓰지 않도록 합니다.
자체적인 낙관적 잠금 전략을 구현할 수 있지만 AWS SDK for Java에서는 @DynamoDBVersionAttribute
주석을 제공합니다. 테이블 매핑 클래스에서 버전 번호를 저장할 속성을 하나 지정하여 이 주석을 사용해 표시하면 됩니다. 그러면 객체를 저장할 때 DynamoDB 테이블의 해당 항목이 버전 번호를 저장하는 속성을 갖게 됩니다. 처음 객체를 저장할 때 DynamoDBMapper
가 버전 번호를 할당하고, 이후 항목을 업데이트할 때마다 버전 번호가 일정하게 자동으로 오릅니다. 업데이트 또는 삭제 요청은 클라이언트 측 객체 버전이 DynamoDB 테이블의 해당 항목 버전 번호와 일치해야만 가능합니다.
다음의 경우 ConditionalCheckFailedException
이 발생합니다.
-
@DynamoDBVersionAttribute
를 이용한 낙관적 잠금을 사용하며, 서버의 버전 값이 클라이언트 측의 값과 다를 경우 -
DynamoDBSaveExpression
과 함께DynamoDBMapper
를 사용하여 데이터를 저장하는 동안 고유의 조건부 제약 조건을 지정하며 이러한 제약 조건이 실패한 경우
참고
-
DynamoDB 전역 테이블은 동시 업데이트 간에 "last writer wins" 조정을 사용합니다. 전역 테이블을 사용할 경우 last writer 정책을 우선 적용합니다. 따라서 잠금 전략이 작동하지 않습니다.
-
DynamoDBMapper
트랜잭션 쓰기 작업은 동일한 객체에 대해@DynamoDBVersionAttribute
주석 및 조건 표현식을 지원하지 않습니다. 트랜잭션 쓰기 내 객체에@DynamoDBVersionAttribute
주석이 추가되고 조건식도 있는 경우에는 SdkClientException이 발생합니다.
예를 들어, 다음 Java 코드에서는 몇 가지 속성이 있는 CatalogItem
클래스를 정의합니다. Version
속성이 @DynamoDBVersionAttribute
주석으로 표시되어 있습니다.
예
@DynamoDBTable(tableName="ProductCatalog") public class CatalogItem { private Integer id; private String title; private String ISBN; private Set<String> bookAuthors; private String someProp; private Long version; @DynamoDBHashKey(attributeName="Id") public Integer getId() { return id; } public void setId(Integer Id) { this.id = Id; } @DynamoDBAttribute(attributeName="Title") public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } @DynamoDBAttribute(attributeName="ISBN") public String getISBN() { return ISBN; } public void setISBN(String ISBN) { this.ISBN = ISBN;} @DynamoDBAttribute(attributeName = "Authors") public Set<String> getBookAuthors() { return bookAuthors; } public void setBookAuthors(Set<String> bookAuthors) { this.bookAuthors = bookAuthors; } @DynamoDBIgnore public String getSomeProp() { return someProp;} public void setSomeProp(String someProp) {this.someProp = someProp;} @DynamoDBVersionAttribute public Long getVersion() { return version; } public void setVersion(Long version) { this.version = version;} }
@DynamoDBVersionAttribute
주석을 Long
이나 Integer
같이 null이 허용된 형식을 제공하는 기본 래퍼 클래스에서 제공하는 null 형식에 적용할 수 있습니다.
낙관적 잠금 전략은 이러한 DynamoDBMapper
메서드에 아래와 같은 영향을 끼칩니다.
-
save
- 새 항목의 경우DynamoDBMapper
는 초기 버전 번호로 1을 할당합니다. 항목을 검색하고, 해당 속성 중 하나 이상을 업데이트하고, 변경 사항 저장을 시도하면 클라이언트 측 버전 번호와 서버 측 버전 번호가 일치하는 경우에만 저장 작업이 성공합니다. 그런 다음DynamoDBMapper
가 버전 번호를 자동으로 일정하게 올립니다. -
delete
-delete
메서드가 객체를 파라미터로 사용하고DynamoDBMapper
가 항목을 삭제하기 전에 버전을 검사합니다. 요청 시DynamoDBMapperConfig.SaveBehavior.CLOBBER
를 지정하면 버전 검사는 비활성화됩니다.DynamoDBMapper
에서 낙관적 잠금을 내부 구현할 경우에는 DynamoDB가 제공하는 조건부 업데이트와 조건부 삭제 지원을 사용합니다. -
transactionWrite
—-
Put
- 새 항목의 경우DynamoDBMapper
는 초기 버전 번호로 1을 할당합니다. 이후 항목을 가져와 속성을 하나 이상 업데이트한 후 변경 사항을 저장하려고 해도 클라이언트 측과 서버 쪽의 버전 번호가 일치해야만 넣기 작업이 가능합니다. 그런 다음DynamoDBMapper
가 버전 번호를 자동으로 일정하게 올립니다. -
Update
- 새 항목의 경우DynamoDBMapper
는 초기 버전 번호로 1을 할당합니다. 이후 항목을 가져와 속성을 하나 이상 업데이트한 후 변경 사항을 저장하려고 해도 클라이언트 측과 서버 쪽의 버전 번호가 일치해야만 업데이트 작업이 가능합니다. 그런 다음DynamoDBMapper
가 버전 번호를 자동으로 일정하게 올립니다. -
Delete
-DynamoDBMapper
는 항목을 삭제하기 전에 버전을 확인합니다. 클라이언트 측과 서버 측 버전 번호가 일치할 경우에만 삭제 작업이 가능합니다. -
ConditionCheck
-@DynamoDBVersionAttribute
주석은ConditionCheck
작업에 지원되지 않습니다.ConditionCheck
항목에@DynamoDBVersionAttribute
주석이 추가될 때 SdkClientException이 발생합니다.
-
낙관적 잠금 비활성화
낙관적 잠금은 DynamoDBMapperConfig.SaveBehavior
열거 값을 UPDATE
에서 CLOBBER
로 변경하면 비활성화할 수 있습니다. 그런 다음 버전 검사를 제외한 DynamoDBMapperConfig
인스턴스를 생성하여 모든 요청에 사용하면 됩니다. DynamoDBMapperConfig.SaveBehavior
와 그 밖에 옵션으로 제공되는 DynamoDBMapper
파라미터에 대한 자세한 내용은 DynamoDBMapper의 구성 설정(선택 사항) 단원을 참조하세요.
또한 잠금 기능을 특정 작업에만 설정할 수도 있습니다. 예를 들어 다음은 DynamoDBMapper
를 사용하여 카탈로그 항목을 저장하는 Java 코드 조각입니다. 이 조각을 보면 옵션인 DynamoDBMapperConfig
파라미터를 save
메서드에 추가하여 DynamoDBMapperConfig.SaveBehavior
를 지정하고 있습니다.
참고
transactionWrite 메서드는 DynamoDBMapperConfig.SaveBehavior 구성을 지원하지 않습니다. transactionWrite의 낙관적 잠금 비활성화는 지원되지 않습니다.
예
DynamoDBMapper mapper = new DynamoDBMapper(client); // Load a catalog item. CatalogItem item = mapper.load(CatalogItem.class, 101); item.setTitle("This is a new title for the item"); ... // Save the item. mapper.save(item, new DynamoDBMapperConfig( DynamoDBMapperConfig.SaveBehavior.CLOBBER));