기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.
트랜잭션 작업 수행
DynamoDB 향상된 클라이언트 API는 transactGetItems()
및 transactWriteItems()
메서드를 제공합니다. Java용 SDK의 트랜잭션 방법은 DynamoDB 테이블에 ACID(원자성, 일관성, 격리 및 내구성)를 제공하여 애플리케이션에서 데이터 정확성을 유지하는 데 도움이 됩니다.
transactGetItems()
예
transactGetItems()
메서드는 항목에 대한 개별 요청을 최대 100개까지 수락합니다. 단일 아토믹 트랜잭션으로 모든 항목을 읽습니다. Amazon DynamoDB 개발자 안내서에는 transactGetItems()
메서드 실패를 유발하는 조건에 대한 정보와 transactGetItem()
호출 시 사용되는 격리 수준에 대한 정보가 있습니다.
다음 예제의 주석 줄 1 다음에, 코드는 builder
매개변수를 사용하여 transactGetItems()
메서드를 호출합니다. SDK가 최종 요청을 생성하는 데 사용할 키 값이 포함된 데이터 객체를 사용하여 빌더 addGetItem()
를 세 번 호출합니다.
요청은 주석 줄 2 다음에 Document
객체 목록을 반환합니다. 반환되는 문서 목록에는 요청된 순서와 동일한 순서로 항목 데이터의 null이 아닌 DocumentDocument.getItem(MappedTableResource<T> mappedTableResource)
메서드는 항목 데이터가 반환된 경우 형식화되지 않은 Document
객체를 형식이 지정된 Java 객체로 변환하고, 그렇지 않으면 null을 반환합니다.
public static void transactGetItemsExample(DynamoDbEnhancedClient enhancedClient, DynamoDbTable<ProductCatalog> catalogTable, DynamoDbTable<MovieActor> movieActorTable) { // 1. Request three items from two tables using a builder. final List<Document> documents = enhancedClient.transactGetItems(b -> b .addGetItem(catalogTable, Key.builder().partitionValue(2).sortValue("Title 55").build()) .addGetItem(movieActorTable, Key.builder().partitionValue("Sophie's Choice").sortValue("Meryl Streep").build()) .addGetItem(movieActorTable, Key.builder().partitionValue("Blue Jasmine").sortValue("Cate Blanchett").build()) .build()); // 2. A list of Document objects is returned in the same order as requested. ProductCatalog title55 = documents.get(0).getItem(catalogTable); if (title55 != null) { logger.info(title55.toString()); } MovieActor sophiesChoice = documents.get(1).getItem(movieActorTable); if (sophiesChoice != null) { logger.info(sophiesChoice.toString()); } // 3. The getItem() method returns null if the Document object contains no item from DynamoDB. MovieActor blueJasmine = documents.get(2).getItem(movieActorTable); if (blueJasmine != null) { logger.info(blueJasmine.toString()); } }
코드 예제가 실행되기 전에 DynamoDB 테이블에는 다음 항목이 포함되어 있습니다.
ProductCatalog{id=2, title='Title 55', isbn='orig_isbn', authors=[b, g], price=10}
MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
다음 출력이 반환됩니다. 항목을 요청했지만 찾을 수 없는 경우 이름이 Blue Jasmine
로 지정된 영화에 대한 요청의 경우와 마찬가지로 항목이 반환되지 않습니다.
ProductCatalog{id=2, title='Title 55', isbn='orig_isbn', authors=[b, g], price=10}
MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
transactWriteItems()
예제
transactWriteItems()
는 여러 테이블에 걸친 단일 아토믹 트랜잭션으로 최대 100개의 추가, 업데이트 또는 삭제 작업을 허용합니다. Amazon DynamoDB 개발자 안내서에는 기본 DynamoDB 서비스 작업의 제한 및 장애 조건에 대한 세부 정보가 포함되어 있습니다.
기본 예제
다음 예제에서는 2개의 테이블에 대해 4개의 작업이 요청됩니다. 해당 모델 클래스 ProductCatalog 및 MovieActor는 이전에 표시된 바 있습니다.
세 가지 가능한 작업(put, update, delete)은 각각 전용 요청 매개변수를 사용하여 세부 정보를 지정합니다.
주석 줄 1 뒤의 코드는 addPutItem()
메서드의 단순한 변형을 보여줍니다. 메서드는 입력할 MappedTableResource
개체와 데이터 객체 인스턴스를 받아들입니다. 주석 줄 2 뒤의 명령문은 TransactPutItemEnhancedRequest
인스턴스를 허용하는 변형을 보여줍니다. 이 변형을 사용하면 요청에 조건 표현식과 같은 더 많은 옵션을 추가할 수 있습니다. 다음 예제에서는 개별 작업에 대한 조건식을 보여줍니다.
주석 줄 3 다음에 업데이트 작업이 요청됩니다. TransactUpdateItemEnhancedRequest
에는 SDK가 모델 객체의 null
값으로 수행하는 작업을 구성할 수 있는 ignoreNulls()
메서드가 있습니다. ignoreNulls()
메서드가 true를 반환하는 경우 SDK는 null
인 데이터 객체 속성에 대한 테이블의 속성 값을 제거하지 않습니다. ignoreNulls()
메서드가 false를 반환하면 SDK는 DynamoDB 서비스에 테이블의 항목에서 속성을 제거하도록 요청합니다. ignoreNulls
의 기본값은 false입니다.
주석 줄 4 다음의 명령문은 데이터 객체를 취하는 삭제 요청의 변형을 보여줍니다. 향상된 클라이언트는 최종 요청을 발송하기 전에 키 값을 추출합니다.
public static void transactWriteItems(DynamoDbEnhancedClient enhancedClient, DynamoDbTable<ProductCatalog> catalogTable, DynamoDbTable<MovieActor> movieActorTable) { enhancedClient.transactWriteItems(b -> b // 1. Simplest variation of put item request. .addPutItem(catalogTable, getProductCatId2()) // 2. Put item request variation that accommodates condition expressions. .addPutItem(movieActorTable, TransactPutItemEnhancedRequest.builder(MovieActor.class) .item(getMovieActorStreep()) .conditionExpression(Expression.builder().expression("attribute_not_exists (movie)").build()) .build()) // 3. Update request that does not remove attribute values on the table if the data object's value is null. .addUpdateItem(catalogTable, TransactUpdateItemEnhancedRequest.builder(ProductCatalog.class) .item(getProductCatId4ForUpdate()) .ignoreNulls(Boolean.TRUE) .build()) // 4. Variation of delete request that accepts a data object. The key values are extracted for the request. .addDeleteItem(movieActorTable, getMovieActorBlanchett()) ); }
다음 도우미 메서드는 add*Item
매개 변수에 대한 데이터 개체를 제공합니다.
public static ProductCatalog getProductCatId2() { return ProductCatalog.builder() .id(2) .isbn("1-565-85698") .authors(new HashSet<>(Arrays.asList("a", "b"))) .price(BigDecimal.valueOf(30.22)) .title("Title 55") .build(); } public static ProductCatalog getProductCatId4ForUpdate() { return ProductCatalog.builder() .id(4) .price(BigDecimal.valueOf(40.00)) .title("Title 1") .build(); } public static MovieActor getMovieActorBlanchett() { MovieActor movieActor = new MovieActor(); movieActor.setActorName("Cate Blanchett"); movieActor.setMovieName("Tar"); movieActor.setActingYear(2022); movieActor.setActingAward("Best Actress"); movieActor.setActingSchoolName("National Institute of Dramatic Art"); return movieActor; } public static MovieActor getMovieActorStreep() { MovieActor movieActor = new MovieActor(); movieActor.setActorName("Meryl Streep"); movieActor.setMovieName("Sophie's Choice"); movieActor.setActingYear(1982); movieActor.setActingAward("Best Actress"); movieActor.setActingSchoolName("Yale School of Drama"); return movieActor; }
코드 예제가 실행되기 전에 DynamoDB 테이블에는 다음 항목이 포함되어 있습니다.
1 | ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
2 | MovieActor{movieName='Tar', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2022, actingSchoolName='National Institute of Dramatic Art'}
코드 실행이 완료된 후 테이블에 다음 항목이 표시됩니다.
3 | ProductCatalog{id=2, title='Title 55', isbn='1-565-85698', authors=[a, b], price=30.22}
4 | ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=40.0}
5 | MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
2행 항목은 삭제되었으며, 3행과 5행에는 추가된 항목이 표시됩니다. 4행에는 라인 1의 업데이트 내용이 표시됩니다. price
값은 항목에서 변경된 유일한 값입니다. ignoreNulls()
가 false를 반환했다면 4행은 다음 줄처럼 보일 것입니다.
ProductCatalog{id=4, title='Title 1', isbn='null', authors=null, price=40.0}
조건 검사 예제
다음 예에서는 조건 검사의 사용을 보여줍니다. 조건 검사는 항목이 있는지 확인하거나 데이터베이스의 항목의 특정 속성에 대한 조건을 검사하는 데 사용됩니다. 조건 확인에서 확인한 항목은 해당 거래의 다른 작업에 사용할 수 없습니다.
참고
동일한 트랜잭션 내에서 동일한 항목을 여러 작업의 대상으로 지정할 수 없습니다. 예를 들어 동일한 트랜잭션에서 조건 확인과 동일한 항목 업데이트를 동시에 수행할 수 없습니다.
이 예에서는 트랜잭션 쓰기 항목 요청의 각 작업 유형 중 하나를 보여줍니다. addConditionCheck()
메서드는 주석 줄 2 다음에 conditionExpression
매개 변수가 false
로 평가될 경우 트랜잭션을 실패시키는 조건을 제공합니다. Helper 메서드 블록에 표시된 메서드에서 반환되는 조건 표현식은 영화 Sophie's
Choice
의 수상 연도가 1982
과 같지 않은지 확인합니다. 값이 맞으면 표현식이 false
까지 평가되고 트랜잭션이 실패합니다.
이 가이드에서는 다른 항목에서 표현식에 대해 자세히 설명합니다.
public static void conditionCheckFailExample(DynamoDbEnhancedClient enhancedClient, DynamoDbTable<ProductCatalog> catalogTable, DynamoDbTable<MovieActor> movieActorTable) { try { enhancedClient.transactWriteItems(b -> b // 1. Perform one of each type of operation with the next three methods. .addPutItem(catalogTable, TransactPutItemEnhancedRequest.builder(ProductCatalog.class) .item(getProductCatId2()).build()) .addUpdateItem(catalogTable, TransactUpdateItemEnhancedRequest.builder(ProductCatalog.class) .item(getProductCatId4ForUpdate()) .ignoreNulls(Boolean.TRUE).build()) .addDeleteItem(movieActorTable, TransactDeleteItemEnhancedRequest.builder() .key(b1 -> b1 .partitionValue(getMovieActorBlanchett().getMovieName()) .sortValue(getMovieActorBlanchett().getActorName())).build()) // 2. Add a condition check on a table item that is not involved in another operation in this request. .addConditionCheck(movieActorTable, ConditionCheck.builder() .conditionExpression(buildConditionCheckExpression()) .key(k -> k .partitionValue("Sophie's Choice") .sortValue("Meryl Streep")) // 3. Specify the request to return existing values from the item if the condition evaluates to true. .returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD) .build()) .build()); // 4. Catch the exception if the transaction fails and log the information. } catch (TransactionCanceledException ex) { ex.cancellationReasons().stream().forEach(cancellationReason -> { logger.info(cancellationReason.toString()); }); } }
이전 코드 예제에서는 다음과 같은 도우미 메서드를 사용했습니다.
private static Expression buildConditionCheckExpression() { Map<String, AttributeValue> expressionValue = Map.of( ":year", numberValue(1982)); return Expression.builder() .expression("actingyear <> :year") .expressionValues(expressionValue) .build(); } public static ProductCatalog getProductCatId2() { return ProductCatalog.builder() .id(2) .isbn("1-565-85698") .authors(new HashSet<>(Arrays.asList("a", "b"))) .price(BigDecimal.valueOf(30.22)) .title("Title 55") .build(); } public static ProductCatalog getProductCatId4ForUpdate() { return ProductCatalog.builder() .id(4) .price(BigDecimal.valueOf(40.00)) .title("Title 1") .build(); } public static MovieActor getMovieActorBlanchett() { MovieActor movieActor = new MovieActor(); movieActor.setActorName("Cate Blanchett"); movieActor.setMovieName("Blue Jasmine"); movieActor.setActingYear(2013); movieActor.setActingAward("Best Actress"); movieActor.setActingSchoolName("National Institute of Dramatic Art"); return movieActor; }
코드 예제가 실행되기 전에 DynamoDB 테이블에는 다음 항목이 포함되어 있습니다.
1 | ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
2 | MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
3 | MovieActor{movieName='Tar', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2022, actingSchoolName='National Institute of Dramatic Art'}
코드 실행이 완료된 후 테이블에 다음 항목이 표시됩니다.
ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
MovieActor{movieName='Sophie's Choice', actorName='Meryl Streep', actingAward='Best Actress', actingYear=1982, actingSchoolName='Yale School of Drama'}
MovieActor{movieName='Tar', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2022, actingSchoolName='National Institute of Dramatic Art'}
트랜잭션이 실패했기 때문에 테이블의 항목은 변경되지 않은 상태로 유지됩니다. 동영상 Sophie's Choice
의 actingYear
값은 1982
으로, transactWriteItem()
메서드가 호출되기 전 테이블 항목의 2행에 표시된 것과 같습니다.
트랜잭션에 대한 취소 정보를 캡처하려면 transactWriteItems()
메서드 호출을 try
블록으로 묶고 TransactionCanceledException
catch
합니다. 예제의 주석 줄 4 다음에 코드가 각 CancellationReason
객체를 기록합니다. 예제의 주석 줄 3 뒤에 오는 코드에서는 트랜잭션 실패를 초래한 항목에 대해 값을 반환하도록 지정하기 때문에 로그에는 Sophie's
Choice
영화 항목에 대한 원시 데이터베이스 값이 표시됩니다.
CancellationReason(Code=None) CancellationReason(Code=None) CancellationReason(Code=None) CancellationReason(Item={actor=AttributeValue(S=Meryl Streep), movie=AttributeValue(S=Sophie's Choice), actingaward=AttributeValue(S=Best Actress), actingyear=AttributeValue(N=1982), actingschoolname=AttributeValue(S=Yale School of Drama)}, ¬ Code=ConditionalCheckFailed, Message=The conditional request failed.)
단일 작업 조건 예제
다음 예제는 트랜잭션 요청의 단일 작업에 대한 조건 사용을 보여줍니다. 주석 라인 1 이후의 삭제 작업에는 데이터베이스에 대해 작업의 대상 항목 값을 확인하는 조건이 포함되어 있습니다. 이 예제에서 주석 행 2 다음에 도우미 메서드를 사용하여 생성된 조건식은 영화의 개봉 연도가 2013년이 아닌 경우 데이터베이스에서 항목을 삭제해야 함을 지정합니다.
표현식은 이 가이드의 뒷부분에서 설명합니다.
public static void singleOperationConditionFailExample(DynamoDbEnhancedClient enhancedClient, DynamoDbTable<ProductCatalog> catalogTable, DynamoDbTable<MovieActor> movieActorTable) { try { enhancedClient.transactWriteItems(b -> b .addPutItem(catalogTable, TransactPutItemEnhancedRequest.builder(ProductCatalog.class) .item(getProductCatId2()) .build()) .addUpdateItem(catalogTable, TransactUpdateItemEnhancedRequest.builder(ProductCatalog.class) .item(getProductCatId4ForUpdate()) .ignoreNulls(Boolean.TRUE).build()) // 1. Delete operation that contains a condition expression .addDeleteItem(movieActorTable, TransactDeleteItemEnhancedRequest.builder() .key((Key.Builder k) -> { MovieActor blanchett = getMovieActorBlanchett(); k.partitionValue(blanchett.getMovieName()) .sortValue(blanchett.getActorName()); }) .conditionExpression(buildDeleteItemExpression()) .returnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD) .build()) .build()); } catch (TransactionCanceledException ex) { ex.cancellationReasons().forEach(cancellationReason -> logger.info(cancellationReason.toString())); } } // 2. Provide condition expression to check if 'actingyear' is not equal to 2013. private static Expression buildDeleteItemExpression() { Map<String, AttributeValue> expressionValue = Map.of( ":year", numberValue(2013)); return Expression.builder() .expression("actingyear <> :year") .expressionValues(expressionValue) .build(); }
이전 코드 예제에서는 다음과 같은 도우미 메서드를 사용했습니다.
public static ProductCatalog getProductCatId2() { return ProductCatalog.builder() .id(2) .isbn("1-565-85698") .authors(new HashSet<>(Arrays.asList("a", "b"))) .price(BigDecimal.valueOf(30.22)) .title("Title 55") .build(); } public static ProductCatalog getProductCatId4ForUpdate() { return ProductCatalog.builder() .id(4) .price(BigDecimal.valueOf(40.00)) .title("Title 1") .build(); } public static MovieActor getMovieActorBlanchett() { MovieActor movieActor = new MovieActor(); movieActor.setActorName("Cate Blanchett"); movieActor.setMovieName("Blue Jasmine"); movieActor.setActingYear(2013); movieActor.setActingAward("Best Actress"); movieActor.setActingSchoolName("National Institute of Dramatic Art"); return movieActor; }
코드 예제가 실행되기 전에 DynamoDB 테이블에는 다음 항목이 포함되어 있습니다.
1 | ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
2 | MovieActor{movieName='Blue Jasmine', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2013, actingSchoolName='National Institute of Dramatic Art'}
코드 실행이 완료된 후 테이블에 다음 항목이 표시됩니다.
ProductCatalog{id=4, title='Title 1', isbn='orig_isbn', authors=[b, g], price=10}
2023-03-15 11:29:07 [main] INFO org.example.tests.TransactDemoTest:168 - MovieActor{movieName='Blue Jasmine', actorName='Cate Blanchett', actingAward='Best Actress', actingYear=2013, actingSchoolName='National Institute of Dramatic Art'}
트랜잭션이 실패했기 때문에 테이블의 항목은 변경되지 않은 상태로 유지됩니다. 영화 Blue Jasmine
의 actingYear
값은 코드 예제가 실행되기 전 항목 목록의 2행에 표시된 것과 같은 2013
입니다.
다음 줄이 콘솔에 기록됩니다.
CancellationReason(Code=None) CancellationReason(Code=None) CancellationReason(Item={actor=AttributeValue(S=Cate Blanchett), movie=AttributeValue(S=Blue Jasmine), actingaward=AttributeValue(S=Best Actress), actingyear=AttributeValue(N=2013), actingschoolname=AttributeValue(S=National Institute of Dramatic Art)}, Code=ConditionalCheckFailed, Message=The conditional request failed)