PHP调用DynamoDB PutItem加attribute_not_exists条件脚本中断
PHP调用DynamoDB PutItem加条件表达式时脚本中断问题
问题表现
- 期望通过
ConditionExpression实现「目标数据项不存在才插入」的逻辑,代码执行到PutItem()调用位置直接终止,无法获取返回值。 - 移除
ConditionExpression参数后接口可正常执行,但会覆盖表内已有的同主键数据,不符合业务预期。 - 已确认条件表达式中判断的
serialNumber字段是该表的分区键,语法本身符合DynamoDB规则。
相关代码
触发中断的条件插入代码
$response = $client->putItem(array( 'TableName' => 'tablename', 'Item' => array( 'serialNumber' => array('S' => 'test123'), 'deviceType' => array('S' => '1') ), 'ConditionExpression' => 'attribute_not_exists(serialNumber)' ));
可执行但会覆盖数据的无约束代码
$response = $client->putItem(array( 'TableName' => 'tablename', 'Item' => array( 'serialNumber' => array('S' => 'test123'), 'deviceType' => array('S' => '1') ) ));
根本原因
AWS PHP SDK默认开启异常抛出模式:当ConditionExpression校验不通过(也就是待插入的主键对应数据已经存在)时,SDK不会返回普通的错误响应数组,而是直接抛出Aws\DynamoDb\Exception\DynamoDbException异常。如果代码没有做异常捕获,PHP会直接抛出致命错误终止执行,后续打印$response的逻辑自然不会运行。
你写的条件表达式没有任何问题,就是DynamoDB实现防覆盖插入的标准写法,和分区键配置不存在冲突。
修复方法
用try-catch块包裹PutItem调用,单独识别条件校验失败的场景,和其他服务类错误做区分处理即可:
use Aws\DynamoDb\Exception\DynamoDbException; try { $response = $client->putItem([ 'TableName' => 'tablename', 'Item' => [ 'serialNumber' => ['S' => 'test123'], 'deviceType' => ['S' => '1'] ], 'ConditionExpression' => 'attribute_not_exists(serialNumber)' ]); // 此处逻辑为插入成功,对应数据之前不存在 var_dump($response); } catch (DynamoDbException $e) { if ($e->getAwsErrorCode() === 'ConditionalCheckFailedException') { // 此处逻辑为数据已存在,未执行插入,可按需做后续处理 echo "目标数据已存在,跳过插入"; } else { // 其他错误:权限不足、表不存在、网络异常等,直接抛出或自定义处理 throw $e; } }
如果不想用异常捕获模式,可以在初始化DynamoDB客户端时传入'throw_exceptions' => false配置,此时条件校验失败的错误信息会直接放在返回的响应数组中,不会终止脚本,但该方式错误处理逻辑相对零散,更推荐使用异常捕获方案。
内容的提问来源于stack exchange,提问作者Lucas Martini
相关产品推荐
相关产品推荐

