Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.
Exécution de transactions DynamoDB dans AWS AppSync
Note
Nous prenons désormais principalement en charge le runtime APPSYNC _JS et sa documentation. Pensez à utiliser le runtime APPSYNC _JS et ses guides ici.
AWS AppSync prend en charge l'utilisation des opérations de transaction Amazon DynamoDB sur une ou plusieurs tables d'une même région. Les opérations prises en charge sont TransactGetItems
et TransactWriteItems
. En utilisant ces fonctionnalités dans AWS AppSync, vous pouvez effectuer des tâches telles que :
-
Transmission d'une liste de clés dans une seule requête et renvoi des résultats à partir d'une table
-
Lecture des enregistrements à partir d'une ou plusieurs tables dans une seule requête
-
Écrire les enregistrements d'une transaction sur une ou plusieurs tables d'une all-or-nothing manière ou d'une autre
-
Exécuter des transactions lorsque certaines conditions sont remplies
Autorisations
Comme les autres résolveurs, vous devez créer une source de données dans AWS AppSync et soit créer un rôle, soit utiliser un rôle existant. Les opérations de transaction nécessitant des autorisations différentes sur les tables DynamoDB, vous devez accorder au rôle configuré des autorisations pour les actions de lecture ou d'écriture :
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "dynamodb:DeleteItem", "dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:Query", "dynamodb:Scan", "dynamodb:UpdateItem" ], "Effect": "Allow", "Resource": [ "arn:aws:dynamodb:region:accountId:table/TABLENAME", "arn:aws:dynamodb:region:accountId:table/TABLENAME/*" ] } ] }
Remarque : Les rôles sont liés aux sources de données dans une source de données AWS AppSync, et les résolveurs de champs sont invoqués par rapport à une source de données. Pour simplifier la configuration, une seule table est spécifiée pour les sources de données configurées pour effectuer une extraction par rapport à DynamoDB. Par conséquent, lorsque vous effectuez une opération de transaction sur plusieurs tables dans un seul résolveur (ce qui constitue une tâche plus avancée), vous devez accorder au rôle associé à cette source de données l'accès à toutes les tables avec lesquelles le résolveur devra interagir. Cela se ferait dans le champ Ressource de la IAM politique ci-dessus. La configuration des appels de transactions sur les tables doit être effectuée dans le modèle de résolveur, dont vous trouverez la description ci-dessous.
Source de données
Dans un souci de simplicité, nous allons utiliser la même source de données pour tous les résolveurs utilisés dans ce didacticiel. Dans l'onglet Sources de données, créez une nouvelle source de données DynamoDB et nommez-la. TransactTutorial Le nom de la table peut être quelconque, car les noms de table sont spécifiés dans le cadre du modèle de mappage de demande pour les opérations de transaction. Nous allons nommer la table empty
.
Nous aurons deux tables appelées savingAccountset checkingAccounts, toutes deux avec accountNumber
comme clé de partition, et une transactionHistorytable avec transactionId
comme clé de partition.
Dans le cadre de ce didacticiel, n'importe quel rôle avec la stratégie en ligne suivante fonctionne. Remplacez region
et accountId
par votre région et votre numéro de compte :
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "dynamodb:DeleteItem", "dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:Query", "dynamodb:Scan", "dynamodb:UpdateItem" ], "Effect": "Allow", "Resource": [ "arn:aws:dynamodb:region:accountId:table/savingAccounts", "arn:aws:dynamodb:region:accountId:table/savingAccounts/*", "arn:aws:dynamodb:region:accountId:table/checkingAccounts", "arn:aws:dynamodb:region:accountId:table/checkingAccounts/*", "arn:aws:dynamodb:region:accountId:table/transactionHistory", "arn:aws:dynamodb:region:accountId:table/transactionHistory/*" ] } ] }
Transactions
Pour cet exemple, le contexte est une transaction bancaire classique, où nous allons utiliser TransactWriteItems
pour :
-
Transférer de l'argent des comptes d'épargne vers des comptes de contrôle
-
Générer de nouveaux enregistrements de transaction pour chaque transaction
Ensuite, nous allons utiliser TransactGetItems
pour récupérer les détails des comptes d'enregistrement et des comptes de vérification.
Avertissement
TransactWriteItems
n'est pas pris en charge lorsqu'il est utilisé avec la détection et la résolution de conflits. Ces paramètres doivent être désactivés pour éviter d'éventuelles erreurs.
Nous définissons notre schéma GraphQL comme suit :
type SavingAccount { accountNumber: String! username: String balance: Float } type CheckingAccount { accountNumber: String! username: String balance: Float } type TransactionHistory { transactionId: ID! from: String to: String amount: Float } type TransactionResult { savingAccounts: [SavingAccount] checkingAccounts: [CheckingAccount] transactionHistory: [TransactionHistory] } input SavingAccountInput { accountNumber: String! username: String balance: Float } input CheckingAccountInput { accountNumber: String! username: String balance: Float } input TransactionInput { savingAccountNumber: String! checkingAccountNumber: String! amount: Float! } type Query { getAccounts(savingAccountNumbers: [String], checkingAccountNumbers: [String]): TransactionResult } type Mutation { populateAccounts(savingAccounts: [SavingAccountInput], checkingAccounts: [CheckingAccountInput]): TransactionResult transferMoney(transactions: [TransactionInput]): TransactionResult } schema { query: Query mutation: Mutation }
TransactWriteItems - Remplir les comptes
Afin de transférer de l'argent entre les comptes, nous devons remplir la table avec les détails. Nous allons utiliser l'opération GraphQL Mutation.populateAccounts
pour le faire.
Dans la section Schéma, cliquez sur Joindre à côté de l'Mutation.populateAccounts
opération. Accédez à VTL Unit Resolvers, puis choisissez la même source de TransactTutorial
données.
Maintenant, utilisez le modèle de mappage de demande suivant :
Modèle de mappage de demande
#set($savingAccountTransactPutItems = []) #set($index = 0) #foreach($savingAccount in ${ctx.args.savingAccounts}) #set($keyMap = {}) $util.qr($keyMap.put("accountNumber", $util.dynamodb.toString($savingAccount.accountNumber))) #set($attributeValues = {}) $util.qr($attributeValues.put("username", $util.dynamodb.toString($savingAccount.username))) $util.qr($attributeValues.put("balance", $util.dynamodb.toNumber($savingAccount.balance))) #set($index = $index + 1) #set($savingAccountTransactPutItem = {"table": "savingAccounts", "operation": "PutItem", "key": $keyMap, "attributeValues": $attributeValues}) $util.qr($savingAccountTransactPutItems.add($savingAccountTransactPutItem)) #end #set($checkingAccountTransactPutItems = []) #set($index = 0) #foreach($checkingAccount in ${ctx.args.checkingAccounts}) #set($keyMap = {}) $util.qr($keyMap.put("accountNumber", $util.dynamodb.toString($checkingAccount.accountNumber))) #set($attributeValues = {}) $util.qr($attributeValues.put("username", $util.dynamodb.toString($checkingAccount.username))) $util.qr($attributeValues.put("balance", $util.dynamodb.toNumber($checkingAccount.balance))) #set($index = $index + 1) #set($checkingAccountTransactPutItem = {"table": "checkingAccounts", "operation": "PutItem", "key": $keyMap, "attributeValues": $attributeValues}) $util.qr($checkingAccountTransactPutItems.add($checkingAccountTransactPutItem)) #end #set($transactItems = []) $util.qr($transactItems.addAll($savingAccountTransactPutItems)) $util.qr($transactItems.addAll($checkingAccountTransactPutItems)) { "version" : "2018-05-29", "operation" : "TransactWriteItems", "transactItems" : $util.toJson($transactItems) }
Selon le modèle de mappage de réponse suivant :
Modèle de mappage de réponse
#if ($ctx.error) $util.appendError($ctx.error.message, $ctx.error.type, null, $ctx.result.cancellationReasons) #end #set($savingAccounts = []) #foreach($index in [0..2]) $util.qr($savingAccounts.add(${ctx.result.keys[$index]})) #end #set($checkingAccounts = []) #foreach($index in [3..5]) $util.qr($checkingAccounts.add(${ctx.result.keys[$index]})) #end #set($transactionResult = {}) $util.qr($transactionResult.put('savingAccounts', $savingAccounts)) $util.qr($transactionResult.put('checkingAccounts', $checkingAccounts)) $util.toJson($transactionResult)
Enregistrez le résolveur et accédez à la section Requêtes de la AWS AppSync console pour renseigner les comptes.
Exécutez la mutation suivante :
mutation populateAccounts { populateAccounts ( savingAccounts: [ {accountNumber: "1", username: "Tom", balance: 100}, {accountNumber: "2", username: "Amy", balance: 90}, {accountNumber: "3", username: "Lily", balance: 80}, ] checkingAccounts: [ {accountNumber: "1", username: "Tom", balance: 70}, {accountNumber: "2", username: "Amy", balance: 60}, {accountNumber: "3", username: "Lily", balance: 50}, ]) { savingAccounts { accountNumber } checkingAccounts { accountNumber } } }
Nous avons rempli 3 comptes d'épargne et 3 comptes de vérification en une seule mutation.
Utilisez la console DynamoDB pour vérifier que les données apparaissent à la fois dans les savingAccountstables et. checkingAccounts
TransactWriteItems - Transférer de l'argent
Attachez un résolveur au champ transferMoney
avec le modèle de mappage de demande suivant. Notez que les valeurs de amounts
, savingAccountNumbers
et checkingAccountNumbers
sont les mêmes.
#set($amounts = []) #foreach($transaction in ${ctx.args.transactions}) #set($attributeValueMap = {}) $util.qr($attributeValueMap.put(":amount", $util.dynamodb.toNumber($transaction.amount))) $util.qr($amounts.add($attributeValueMap)) #end #set($savingAccountTransactUpdateItems = []) #set($index = 0) #foreach($transaction in ${ctx.args.transactions}) #set($keyMap = {}) $util.qr($keyMap.put("accountNumber", $util.dynamodb.toString($transaction.savingAccountNumber))) #set($update = {}) $util.qr($update.put("expression", "SET balance = balance - :amount")) $util.qr($update.put("expressionValues", $amounts[$index])) #set($index = $index + 1) #set($savingAccountTransactUpdateItem = {"table": "savingAccounts", "operation": "UpdateItem", "key": $keyMap, "update": $update}) $util.qr($savingAccountTransactUpdateItems.add($savingAccountTransactUpdateItem)) #end #set($checkingAccountTransactUpdateItems = []) #set($index = 0) #foreach($transaction in ${ctx.args.transactions}) #set($keyMap = {}) $util.qr($keyMap.put("accountNumber", $util.dynamodb.toString($transaction.checkingAccountNumber))) #set($update = {}) $util.qr($update.put("expression", "SET balance = balance + :amount")) $util.qr($update.put("expressionValues", $amounts[$index])) #set($index = $index + 1) #set($checkingAccountTransactUpdateItem = {"table": "checkingAccounts", "operation": "UpdateItem", "key": $keyMap, "update": $update}) $util.qr($checkingAccountTransactUpdateItems.add($checkingAccountTransactUpdateItem)) #end #set($transactionHistoryTransactPutItems = []) #foreach($transaction in ${ctx.args.transactions}) #set($keyMap = {}) $util.qr($keyMap.put("transactionId", $util.dynamodb.toString(${utils.autoId()}))) #set($attributeValues = {}) $util.qr($attributeValues.put("from", $util.dynamodb.toString($transaction.savingAccountNumber))) $util.qr($attributeValues.put("to", $util.dynamodb.toString($transaction.checkingAccountNumber))) $util.qr($attributeValues.put("amount", $util.dynamodb.toNumber($transaction.amount))) #set($transactionHistoryTransactPutItem = {"table": "transactionHistory", "operation": "PutItem", "key": $keyMap, "attributeValues": $attributeValues}) $util.qr($transactionHistoryTransactPutItems.add($transactionHistoryTransactPutItem)) #end #set($transactItems = []) $util.qr($transactItems.addAll($savingAccountTransactUpdateItems)) $util.qr($transactItems.addAll($checkingAccountTransactUpdateItems)) $util.qr($transactItems.addAll($transactionHistoryTransactPutItems)) { "version" : "2018-05-29", "operation" : "TransactWriteItems", "transactItems" : $util.toJson($transactItems) }
Nous aurons 3 transactions bancaires en une seule opération TransactWriteItems
. Utilisez le modèle de mappage de réponse suivant :
#if ($ctx.error) $util.appendError($ctx.error.message, $ctx.error.type, null, $ctx.result.cancellationReasons) #end #set($savingAccounts = []) #foreach($index in [0..2]) $util.qr($savingAccounts.add(${ctx.result.keys[$index]})) #end #set($checkingAccounts = []) #foreach($index in [3..5]) $util.qr($checkingAccounts.add(${ctx.result.keys[$index]})) #end #set($transactionHistory = []) #foreach($index in [6..8]) $util.qr($transactionHistory.add(${ctx.result.keys[$index]})) #end #set($transactionResult = {}) $util.qr($transactionResult.put('savingAccounts', $savingAccounts)) $util.qr($transactionResult.put('checkingAccounts', $checkingAccounts)) $util.qr($transactionResult.put('transactionHistory', $transactionHistory)) $util.toJson($transactionResult)
Accédez maintenant à la section Requêtes de la AWS AppSync console et exécutez la transferMoneymutation comme suit :
mutation write { transferMoney( transactions: [ {savingAccountNumber: "1", checkingAccountNumber: "1", amount: 7.5}, {savingAccountNumber: "2", checkingAccountNumber: "2", amount: 6.0}, {savingAccountNumber: "3", checkingAccountNumber: "3", amount: 3.3} ]) { savingAccounts { accountNumber } checkingAccounts { accountNumber } transactionHistory { transactionId } } }
Nous avons envoyé 2 transactions bancaires en une seule mutation. Utilisez la console DynamoDB pour vérifier que les données apparaissent dans savingAccountsles tables checkingAccounts, et. transactionHistory
TransactGetItems - Récupérer des comptes
Afin de récupérer les détails des comptes d'enregistrement et de vérification dans une seule requête transactionnelle, nous attacherons un résolveur à l'opération Query.getAccounts
GraphQL sur notre schéma. Sélectionnez Joindre, accédez à VTL Unit Resolvers, puis sur l'écran suivant, sélectionnez la même source de TransactTutorial
données créée au début du didacticiel. Configurez les modèles comme suit :
Modèle de mappage de demande
#set($savingAccountsTransactGets = []) #foreach($savingAccountNumber in ${ctx.args.savingAccountNumbers}) #set($savingAccountKey = {}) $util.qr($savingAccountKey.put("accountNumber", $util.dynamodb.toString($savingAccountNumber))) #set($savingAccountTransactGet = {"table": "savingAccounts", "key": $savingAccountKey}) $util.qr($savingAccountsTransactGets.add($savingAccountTransactGet)) #end #set($checkingAccountsTransactGets = []) #foreach($checkingAccountNumber in ${ctx.args.checkingAccountNumbers}) #set($checkingAccountKey = {}) $util.qr($checkingAccountKey.put("accountNumber", $util.dynamodb.toString($checkingAccountNumber))) #set($checkingAccountTransactGet = {"table": "checkingAccounts", "key": $checkingAccountKey}) $util.qr($checkingAccountsTransactGets.add($checkingAccountTransactGet)) #end #set($transactItems = []) $util.qr($transactItems.addAll($savingAccountsTransactGets)) $util.qr($transactItems.addAll($checkingAccountsTransactGets)) { "version" : "2018-05-29", "operation" : "TransactGetItems", "transactItems" : $util.toJson($transactItems) }
Modèle de mappage de réponse
#if ($ctx.error) $util.appendError($ctx.error.message, $ctx.error.type, null, $ctx.result.cancellationReasons) #end #set($savingAccounts = []) #foreach($index in [0..2]) $util.qr($savingAccounts.add(${ctx.result.items[$index]})) #end #set($checkingAccounts = []) #foreach($index in [3..4]) $util.qr($checkingAccounts.add($ctx.result.items[$index])) #end #set($transactionResult = {}) $util.qr($transactionResult.put('savingAccounts', $savingAccounts)) $util.qr($transactionResult.put('checkingAccounts', $checkingAccounts)) $util.toJson($transactionResult)
Enregistrez le résolveur et accédez aux sections Requêtes de la AWS AppSync console. Pour récupérer les comptes d'enregistrement et de vérification, exécutez la requête suivante :
query getAccounts { getAccounts( savingAccountNumbers: ["1", "2", "3"], checkingAccountNumbers: ["1", "2"] ) { savingAccounts { accountNumber username balance } checkingAccounts { accountNumber username balance } } }
Nous avons démontré avec succès l'utilisation des transactions DynamoDB à l'aide de. AWS AppSync