本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
在 中執行 DynamoDB 交易 AWS AppSync
AWS AppSync 支援在單一區域中的一或多個資料表使用 Amazon DynamoDB 交易操作。支援的操作包括 TransactGetItems
和 TransactWriteItems
。透過在 中使用這些功能 AWS AppSync,您可以執行下列任務:
-
在單一查詢中傳遞金鑰清單,並從資料表傳回結果
-
從單一查詢中的一或多個資料表讀取記錄
-
將 all-or-nothing交易中的記錄寫入一個或多個資料表
-
滿足某些條件時執行交易
許可
與其他解析程式一樣,您需要在 中建立資料來源, AWS AppSync 並建立角色或使用現有的資料來源。由於交易操作在 DynamoDB 資料表上需要不同的許可,因此您需要為讀取或寫入動作授予已設定的角色許可:
{ "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/*" ] } ] }
注意
角色會與 中的資料來源綁定 AWS AppSync,而 欄位上的解析程式會針對資料來源叫用。設定為針對 DynamoDB 擷取的資料來源只有一個指定的資料表,以保持組態簡單。因此,在單一解析程式中針對多個資料表執行交易操作時 (這是一項更為進階的工作),您必須授予權限給該資料來源上的角色,以存取解析程式將會與其互動的所有資料表。這將在上述IAM政策的資源欄位中完成。針對資料表的交易呼叫組態是在解析程式程式碼中完成,我們如下所述。
資料來源
為簡單起見,我們將針對本教學課程中使用的所有解析程式,使用相同的資料來源。
我們將有兩個名為 savingAccounts和 的資料表checkingAccounts,兩個資料表都以 accountNumber
作為分割區金鑰,而一個transactionHistory資料表則以 transactionId
作為分割區金鑰。您可以使用下列CLI命令來建立資料表。請務必將 取代region
為您的 區域。
使用 CLI
aws dynamodb create-table --table-name savingAccounts \ --attribute-definitions AttributeName=accountNumber,AttributeType=S \ --key-schema AttributeName=accountNumber,KeyType=HASH \ --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \ --table-class STANDARD --region region aws dynamodb create-table --table-name checkingAccounts \ --attribute-definitions AttributeName=accountNumber,AttributeType=S \ --key-schema AttributeName=accountNumber,KeyType=HASH \ --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \ --table-class STANDARD --region region aws dynamodb create-table --table-name transactionHistory \ --attribute-definitions AttributeName=transactionId,AttributeType=S \ --key-schema AttributeName=transactionId,KeyType=HASH \ --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \ --table-class STANDARD --region region
在 AWS AppSync 主控台的資料來源 中,建立新的 DynamoDB 資料來源並命名為 TransactTutorial。選取 savingAccounts作為資料表 (雖然使用交易時特定資料表並不重要)。選擇建立新的角色和資料來源。您可以檢閱資料來源組態,以查看產生的角色名稱。在IAM主控台中,您可以新增內嵌政策,允許資料來源與所有資料表互動。
將 region
和 取代accountID
為您的區域和帳戶 ID:
{ "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/*" ] } ] }
交易
在此範例中,內容是傳統的銀行交易,我們將使用 TransactWriteItems
以進行下列操作:
-
從存款帳戶轉帳至支票帳戶
-
為每筆交易產生新的交易記錄
然後,我們會使用 TransactGetItems
擷取存款帳戶和支票帳戶中的詳細資料。
警告
TransactWriteItems
與衝突偵測和解決方案搭配使用時,不支援 。必須停用這些設定,以防止可能的錯誤。
定義 GraphQl 結構描述,如下所示:
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 }
TransactWriteItems - 填入帳戶
為了在帳戶之間轉帳,我們需要在表格中填入詳細資料。我們將使用 GraphQL 操作 Mutation.populateAccounts
來執行此作業。
在結構描述區段中,按一下Mutation.populateAccounts
操作旁的附加。選擇TransactTutorial
資料來源,然後選擇建立 。
現在請使用下列程式碼:
import { util } from '@aws-appsync/utils' export function request(ctx) { const { savingAccounts, checkingAccounts } = ctx.args const savings = savingAccounts.map(({ accountNumber, ...rest }) => { return { table: 'savingAccounts', operation: 'PutItem', key: util.dynamodb.toMapValues({ accountNumber }), attributeValues: util.dynamodb.toMapValues(rest), } }) const checkings = checkingAccounts.map(({ accountNumber, ...rest }) => { return { table: 'checkingAccounts', operation: 'PutItem', key: util.dynamodb.toMapValues({ accountNumber }), attributeValues: util.dynamodb.toMapValues(rest), } }) return { version: '2018-05-29', operation: 'TransactWriteItems', transactItems: [...savings, ...checkings], } } export function response(ctx) { if (ctx.error) { util.error(ctx.error.message, ctx.error.type, null, ctx.result.cancellationReasons) } const { savingAccounts: sInput, checkingAccounts: cInput } = ctx.args const keys = ctx.result.keys const savingAccounts = sInput.map((_, i) => keys[i]) const sLength = sInput.length const checkingAccounts = cInput.map((_, i) => keys[sLength + i]) return { savingAccounts, checkingAccounts } }
儲存解析器並導覽至 AWS AppSync 主控台的查詢區段以填入帳戶。
執行下列的變動:
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 } } }
我們在一個突變中填入三個儲存帳戶和三個檢查帳戶。
使用 DynamoDB 主控台來驗證資料是否同時顯示在 savingAccounts和 checkingAccounts資料表中。
TransactWriteItems - 轉帳
使用下列程式碼將解析器連接至 transferMoney
突變。對於每次轉移,我們需要檢查和儲蓄帳戶的成功修改工具,而且我們需要追蹤交易中的轉移。
import { util } from '@aws-appsync/utils' export function request(ctx) { const transactions = ctx.args.transactions const savings = [] const checkings = [] const history = [] transactions.forEach((t) => { const { savingAccountNumber, checkingAccountNumber, amount } = t savings.push({ table: 'savingAccounts', operation: 'UpdateItem', key: util.dynamodb.toMapValues({ accountNumber: savingAccountNumber }), update: { expression: 'SET balance = balance - :amount', expressionValues: util.dynamodb.toMapValues({ ':amount': amount }), }, }) checkings.push({ table: 'checkingAccounts', operation: 'UpdateItem', key: util.dynamodb.toMapValues({ accountNumber: checkingAccountNumber }), update: { expression: 'SET balance = balance + :amount', expressionValues: util.dynamodb.toMapValues({ ':amount': amount }), }, }) history.push({ table: 'transactionHistory', operation: 'PutItem', key: util.dynamodb.toMapValues({ transactionId: util.autoId() }), attributeValues: util.dynamodb.toMapValues({ from: savingAccountNumber, to: checkingAccountNumber, amount, }), }) }) return { version: '2018-05-29', operation: 'TransactWriteItems', transactItems: [...savings, ...checkings, ...history], } } export function response(ctx) { if (ctx.error) { util.error(ctx.error.message, ctx.error.type, null, ctx.result.cancellationReasons) } const tInput = ctx.args.transactions const tLength = tInput.length const keys = ctx.result.keys const savingAccounts = tInput.map((_, i) => keys[tLength * 0 + i]) const checkingAccounts = tInput.map((_, i) => keys[tLength * 1 + i]) const transactionHistory = tInput.map((_, i) => keys[tLength * 2 + i]) return { savingAccounts, checkingAccounts, transactionHistory } }
現在,導覽至 AWS AppSync 主控台的查詢區段,並執行transferMoney突變,如下所示:
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 } } }
我們傳送了三個具有一個突變的銀行交易。使用 DynamoDB 主控台來驗證資料是否顯示在 savingAccounts、 checkingAccounts和 transactionHistory資料表中。
TransactGetItems - 擷取帳戶
為了從單一交易請求中的儲存和檢查帳戶擷取詳細資訊,我們會將解析器連接至我們結構描述上的 Query.getAccounts
GraphQL 操作。選取連接 ,選取教學課程開始時建立的相同TransactTutorial
資料來源。使用下列程式碼:
import { util } from '@aws-appsync/utils' export function request(ctx) { const { savingAccountNumbers, checkingAccountNumbers } = ctx.args const savings = savingAccountNumbers.map((accountNumber) => { return { table: 'savingAccounts', key: util.dynamodb.toMapValues({ accountNumber }) } }) const checkings = checkingAccountNumbers.map((accountNumber) => { return { table: 'checkingAccounts', key: util.dynamodb.toMapValues({ accountNumber }) } }) return { version: '2018-05-29', operation: 'TransactGetItems', transactItems: [...savings, ...checkings], } } export function response(ctx) { if (ctx.error) { util.error(ctx.error.message, ctx.error.type, null, ctx.result.cancellationReasons) } const { savingAccountNumbers: sInput, checkingAccountNumbers: cInput } = ctx.args const items = ctx.result.items const savingAccounts = sInput.map((_, i) => items[i]) const sLength = sInput.length const checkingAccounts = cInput.map((_, i) => items[sLength + i]) return { savingAccounts, checkingAccounts } }
儲存解析器並導覽至 AWS AppSync 主控台的查詢區段。若要擷取節省和檢查帳戶,請執行下列查詢:
query getAccounts { getAccounts( savingAccountNumbers: ["1", "2", "3"], checkingAccountNumbers: ["1", "2"] ) { savingAccounts { accountNumber username balance } checkingAccounts { accountNumber username balance } } }
我們已成功使用 示範 DynamoDB 交易的使用 AWS AppSync。