自学内容网 自学内容网

dynamodb——事务

目的:提供在同一区域内对跨表的数据项执行原子和可序列化操作的能力,同时保证性能的可预测性,并且不影响非事务性的工作负载。

因此,没有采用传统意义上的交互式事务而是引入了两个新的单请求操作实现一次性事务,即TransactGetItems和TransactWriteItems。

无需其他操作,直接使用api即可支持事务

TransactGetItems

只读事务API,实现从一致的快照中检索多个条目,事务读和任何写操作之间是序列化的

使用

async function testTransactGet() {
    const params = {
        TransactItems: [
            {
                Get: {
                    TableName: userTableName,
                    Key: {
                        user_id: '577fb67c-9330-4336-b0b3-9c7a59ef67a3',
                    },
                    ProjectionExpression: 'user_id,email,creation_time',
                },
            },
            {
                Get: {
                    TableName: orderTableName,
                    Key: {
                        id: '1234',
                    },
                    ProjectionExpression: 'id,user_id,creation_time,esim_info',
                },
            },
            {
                Get: {
                    TableName: orderTableName,
                    Key: {
                        id: 'de886376-fcfb-4acf-b24c-dd19ba13d768',
                    },
                    ProjectionExpression: 'id,user_id,creation_time,esim_info',
                },
            },
        ],
    }
    const resp = await dynamoDb.transactGet(params)

    if (resp.$metadata.httpStatusCode !== 200) {
        console.log(`error`)
    } else {
        console.log(JSON.stringify(resp))
    }
}

{
    "$metadata": {
        "httpStatusCode": 200,
        "requestId": "5COQSMVUIM6SKDJE127IPLK627VV4KQNSO5AEMVJF66Q9ASUAAJG",
        "attempts": 1,
        "totalRetryDelay": 0
    },
    "Responses": [
        {
            "Item": {
                "email": "jing.zhang@getnomad.app",
                "user_id": "577fb67c-9330-4336-b0b3-9c7a59ef67a3",
                "creation_time": "2023-12-14T11:12:36Z"
            }
        },
        {},
        {
            "Item": {
                "esim_info": {
                    "matching_id": "JQ-20G3W1-1LSANYC",
                    "iccid": "8932042000006259105",
                    "require_manual_activate": false,
                    "qr_data": "LPA:1$rsp.truphone.com$JQ-20G3W1-1LSANYC",
                    "smdp_url": "rsp.truphone.com",
                    "support_direct_install": false,
                    "status": "Released",
                    "trust_installation_status": false
                },
                "user_id": "b5f20d65-6f5c-4512-8de5-4eb50dbebfc4",
                "id": "de886376-fcfb-4acf-b24c-dd19ba13d768",
                "creation_time": "2024-03-23T06:08:17Z"
            }
        }
    ]
}
  1. 只能使用主键索引查询,使用其他字段会抛异常:TransactionCanceledException, The provided key element does not match the schema
  2. 同一事务内不能存在相同的条目,属于语法错误,会抛异常:ValidationException: Transaction request cannot include multiple operations on one item
  3. 多个项目的结果按序返回

TransactWriteItems

事务写API,允许在一个或多个表中原子地创建、删除或更新多个条目,支持:Put、Update、Delete 和 ConditionCheck 操作

  • Put — 启动 PutItem 操作以创建一个新项目,或者将旧项目替换为新项目
  • Update — 启动 UpdateItem 操作以编辑现有项目的属性,或者将新项目添加到表中
  • Delete — 启动 DeleteItem 操作,以删除表中由其主键标识的单个项目
  • ConditionCheck — 检查项目是否存在,或者检查项目特定属性的条件

使用

async function testUpdateCondition(clientRequestToken, userTagId) {
  const params = {
    TransactItems: [
      {
        ConditionCheck: {
          TableName: `test.sys.users`,
          Key: {
            user_id: '4ceae1dd-d331-4535-8835-6451f5d5269f',
          },
          ConditionExpression: `attribute_exists(user_id)`,
        },
      },
      {
        Put: {
          TableName: `dev.sys.user_tag`,
          Item: {
            id: userTagId,
            email: 'jing.zhang+testt1@getnomad.app',
            organization_id: 'dea6024b-09ea-4835-9335-4d689be48aae',
            account_tag: 'BT',
            operator_user_id: '577fb67c-9330-4336-b0b3-9c7a59ef67a3',
            creation_time: moment().utc().format(),
          },
        },
      },
      {
        Update: {
          TableName: orderTableName,
          Key: {
            id: '161dd505-1ed7-4384-a666-fa672f942cd5',
          },
          UpdateExpression: 'SET assigned = :expect_value,user_id = :expect_user_id',
          ExpressionAttributeValues: { ':expect_value': true, ':expect_user_id': '4ceae1dd-d331-4535-8835-6451f5d5269f', ':current_assigned': false },
          ConditionExpression: 'assigned = :current_assigned',
        },
      },
    ],
    ClientRequestToken: clientRequestToken,
  }
  const resp = await dynamoDb.transactWrite(params)
  console.log(JSON.stringify(resp))
}
  • ConditionCheck 用于条件检测,必须结合ConditionExpression

幂等-ClientRequestToken

  • 使用方主动传入参数ClientRequestToken
  • 幂等有效期为十分钟
  • 十分钟内使用相同token发起相同参数的请求,会返回成功,实际未做更改
async function testUpdateCondition(clientRequestToken, userTagId) {
    const params = {
        TransactItems: [
            {
                Update: {
                    TableName: userTableName,
                    Key: {
                        user_id: '577fb67c-9330-4336-b0b3-9c7a59ef67a3',
                    },
                    UpdateExpression: 'SET subscribe_to_feed = :expect_value',
                    ExpressionAttributeValues: { ':expect_value': true },
                },
            },
        ],
        ClientRequestToken: clientRequestToken,
        ReturnConsumedCapacity: 'INDEXES',
    }
    const resp = await dynamoDb.transactWrite(params)
    console.log(JSON.stringify(resp))
}
{
  "$metadata": {
    "httpStatusCode": 200,
    "requestId": "KNPADV761709N5G9F9D0P6RMQVVV4KQNSO5AEMVJF66Q9ASUAAJG",
    "attempts": 1,
    "totalRetryDelay": 0
  },
  "ConsumedCapacity": [
    {
      "CapacityUnits": 6,
      "TableName": "test.sys.users",
      "WriteCapacityUnits": 6
    }
  ]
}
{
    "$metadata": {
        "httpStatusCode": 200,
        "requestId": "7J4BO6MQPCIAGTLMU1ICFJ5LRFVV4KQNSO5AEMVJF66Q9ASUAAJG",
        "attempts": 1,
        "totalRetryDelay": 0
    },
    "ConsumedCapacity": [
        {
            "CapacityUnits": 2,
            "ReadCapacityUnits": 2,
            "TableName": "test.sys.users"
        }
    ]
}

相同token相同request 十分钟内再次请求结果成功,但只消耗了2RCU,无WCU的消耗

  • 十分钟内使用相同token发起不同参数的请求会报错:IdempotentParameterMismatchException: Specified idempotent token was used with different request parameters within the idempotency window

dynamoose

await dynamoose.transaction([
  // User.transaction.get({ user_id: '577fb67c-9330-4336-b0b3-9c7a59ef67a3' }),
  User.transaction.condition({ user_id: '4ceae1dd-d331-4535-8835-6451f5d5269f' }, new dynamoose.Condition().where('email').exists()),
  UserTag.transaction.create({
    id: '02f15ff7-38df-4250-a963-3aee1fec9fb3',
    email: 'jing.zhang+testt1@getnomad.app',
    organization_id: 'dea6024b-09ea-4835-9335-4d689be48aae',
    account_tag: 'BT',
    operator_user_id: '577fb67c-9330-4336-b0b3-9c7a59ef67a3',
    creation_time: moment().utc().format(),
  }),
  Order.transaction.update({ id: '161dd505-1ed7-4384-a666-fa672f942cd5' }, { assigned: true, user_id: '4ceae1dd-d331-4535-8835-6451f5d5269f' }),
])

‼️ dynamoose.transaction()入参支持get,condition,put,update,delete;但不支持同时执行get和write,需要使用方自主将两种操作分开调用

决定是write和get的方式

  1. 设置setting.type,但是type定义只有内部声明,没有export,用起来会编译错误,但不影响实际执行

TransactionType

  1. 由dynamoose自主决定,有一条是write即为write,最终由事务校验报错:ValidationException: Invalid Request: TransactWriteRequest should contain Delete or Put or Update request

并发事务的处理

事务冲突

相同数据的事务并发操作,存在事务冲突,即TransactionConflictException:

  1. 事务写和普通写同时执行且包含相同的数据,即 正在进行的TransactWriteItems请求 与 put/update/delete请求包含有相同的数据
  2. 事务写和事务写同时执行且包含相同的数据,即TransactWriteItems 请求中的某个项目是另一个正在进行的 TransactWriteItems 请求的一部分
  3. 事务读和写操作(事务写/普通写)同时执行且包含相同的数据,即TransactGetItems 请求中的某个项目是正在进行的 TransactWriteItems/BatchWriteItem/PutItem/UpdateItem/DeleteItem 请求的一部分

隔离级别

可序列化

当前操作在前一个操作完成之前不会开始执行

  • 在任何事务操作与任何标准写入操作(PutItem、UpdateItem 或 DeleteItem)之间
  • 在任何事务操作与任何标准读取操作 (GetItem) 之间
  • 在 TransactWriteItems 操作与 TransactGetItems 操作之间
读已提交
  • 事务操作与批量普通读(BatchGetItem、Query 或 Scan)之间均为读取已提交,一定不能读取到事务未提交的数据,预期能读取到提交事务的最新结果
  • BatchGetItem和TransactWriteItems是读取已提交,但BatchGetItem中的单个读取和TransactWriteItems整体是序列化的

性能

事务操作对非事务操作的影响只是占据了一定的读写容量,而对于按需的容量模式可以忽略

  • 事务操作和非事务操作是互不干扰的

原文地址:https://blog.csdn.net/Zj_boring/article/details/143776702

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!