DynamoDB删除数据 #
一、DeleteItem概述 #
1.1 基本概念 #
DeleteItem 用于从表中删除单个项目。
text
DeleteItem特点:
├── 删除单个项目
├── 支持条件删除
├── 支持返回被删除的项目
├── 原子操作
└── 项目不存在不报错
1.2 删除方式对比 #
| 方式 | 说明 | 适用场景 |
|---|---|---|
| DeleteItem | 删除单个项目 | 精确删除 |
| BatchWriteItem | 批量删除 | 大量删除 |
| TTL | 自动过期删除 | 定时清理 |
二、基本删除 #
2.1 使用CLI #
简单主键:
bash
aws dynamodb delete-item \
--table-name Users \
--key '{"UserId": {"S": "user123"}}'
复合主键:
bash
aws dynamodb delete-item \
--table-name Orders \
--key '{
"UserId": {"S": "user123"},
"OrderId": {"S": "order001"}
}'
2.2 使用JavaScript SDK #
javascript
const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
const { DynamoDBDocumentClient, DeleteCommand } = require('@aws-sdk/lib-dynamodb');
const client = new DynamoDBClient({ region: 'us-east-1' });
const docClient = DynamoDBDocumentClient.from(client);
// 简单主键
await docClient.send(new DeleteCommand({
TableName: 'Users',
Key: { UserId: 'user123' }
}));
// 复合主键
await docClient.send(new DeleteCommand({
TableName: 'Orders',
Key: {
UserId: 'user123',
OrderId: 'order001'
}
}));
2.3 使用Python SDK #
python
import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Users')
# 简单主键
table.delete_item(
Key={'UserId': 'user123'}
)
# 复合主键
table.delete_item(
Key={
'UserId': 'user123',
'OrderId': 'order001'
}
)
三、条件删除 #
3.1 仅当条件满足时删除 #
bash
aws dynamodb delete-item \
--table-name Users \
--key '{"UserId": {"S": "user123"}}' \
--condition-expression 'IsActive = :active' \
--expression-attribute-values '{":active": {"BOOL": false}}'
javascript
await docClient.send(new DeleteCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
ConditionExpression: 'IsActive = :active',
ExpressionAttributeValues: {
':active': false
}
}));
3.2 常用条件表达式 #
javascript
// 仅当状态为特定值时删除
ConditionExpression: 'Status = :status'
// 仅当版本匹配时删除
ConditionExpression: 'Version = :expectedVersion'
// 仅当属性存在时删除
ConditionExpression: 'attribute_exists(Email)'
// 仅当属性不存在时删除
ConditionExpression: 'attribute_not_exists(DeletedAt)'
// 组合条件
ConditionExpression: 'Status = :status AND CreatedAt < :cutoffDate'
// 集合包含检查
ConditionExpression: 'contains(Tags, :tag)'
3.3 条件删除示例 #
删除非活跃用户:
javascript
async function deleteInactiveUser(userId) {
try {
await docClient.send(new DeleteCommand({
TableName: 'Users',
Key: { UserId: userId },
ConditionExpression: 'IsActive = :inactive',
ExpressionAttributeValues: {
':inactive': false
}
}));
return { success: true };
} catch (error) {
if (error.name === 'ConditionalCheckFailedException') {
return { success: false, error: 'User is still active' };
}
throw error;
}
}
带版本检查的删除:
javascript
async function deleteWithVersion(userId, expectedVersion) {
try {
await docClient.send(new DeleteCommand({
TableName: 'Users',
Key: { UserId: userId },
ConditionExpression: 'Version = :version',
ExpressionAttributeValues: {
':version': expectedVersion
}
}));
return { success: true };
} catch (error) {
if (error.name === 'ConditionalCheckFailedException') {
return { success: false, error: 'Version mismatch' };
}
throw error;
}
}
四、返回值配置 #
4.1 返回被删除的项目 #
javascript
const response = await docClient.send(new DeleteCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
ReturnValues: 'ALL_OLD'
}));
if (response.Attributes) {
console.log('Deleted item:', response.Attributes);
} else {
console.log('Item did not exist');
}
4.2 返回值选项 #
| 选项 | 说明 |
|---|---|
| NONE | 不返回任何值(默认) |
| ALL_OLD | 返回被删除的项目 |
4.3 实用示例 #
javascript
async function deleteUserAndArchive(userId) {
const response = await docClient.send(new DeleteCommand({
TableName: 'Users',
Key: { UserId: userId },
ReturnValues: 'ALL_OLD'
}));
if (response.Attributes) {
// 归档删除的用户数据
await archiveUser(response.Attributes);
return { success: true, deletedUser: response.Attributes };
}
return { success: false, error: 'User not found' };
}
五、批量删除 #
5.1 使用BatchWriteItem #
javascript
const { BatchWriteCommand } = require('@aws-sdk/lib-dynamodb');
async function batchDeleteUsers(userIds) {
const deleteRequests = userIds.map(id => ({
DeleteRequest: {
Key: { UserId: id }
}
}));
await docClient.send(new BatchWriteCommand({
RequestItems: {
Users: deleteRequests
}
}));
}
5.2 处理未处理的项目 #
javascript
async function batchDeleteWithRetry(tableName, keys) {
const deleteRequests = keys.map(key => ({
DeleteRequest: { Key: key }
}));
let requestItems = { [tableName]: deleteRequests };
while (Object.keys(requestItems).length > 0) {
const response = await docClient.send(new BatchWriteCommand({
RequestItems: requestItems
}));
if (response.UnprocessedItems && Object.keys(response.UnprocessedItems).length > 0) {
requestItems = response.UnprocessedItems;
await new Promise(resolve => setTimeout(resolve, 100));
} else {
break;
}
}
}
5.3 BatchWriteItem限制 #
text
限制:
├── 每批最多25个操作
├── 每批最大16MB数据
├── 不支持条件表达式
└── 同一项目不能重复
六、删除大量数据 #
6.1 分批删除 #
javascript
async function deleteAllItems(tableName, partitionKey) {
let lastKey = null;
do {
// 查询一批数据
const queryResponse = await docClient.send(new QueryCommand({
TableName: tableName,
KeyConditionExpression: 'PK = :pk',
ExpressionAttributeValues: { ':pk': partitionKey },
ExclusiveStartKey: lastKey,
Limit: 25
}));
if (queryResponse.Items && queryResponse.Items.length > 0) {
// 批量删除
const deleteRequests = queryResponse.Items.map(item => ({
DeleteRequest: {
Key: { PK: item.PK, SK: item.SK }
}
}));
await docClient.send(new BatchWriteCommand({
RequestItems: {
[tableName]: deleteRequests
}
}));
}
lastKey = queryResponse.LastEvaluatedKey;
} while (lastKey);
}
6.2 使用Scan删除 #
javascript
async function deleteAllItemsByScan(tableName) {
let lastKey = null;
do {
const scanResponse = await docClient.send(new ScanCommand({
TableName: tableName,
ExclusiveStartKey: lastKey,
Limit: 25,
ProjectionExpression: 'PK, SK' // 只获取主键
}));
if (scanResponse.Items && scanResponse.Items.length > 0) {
const deleteRequests = scanResponse.Items.map(item => ({
DeleteRequest: {
Key: { PK: item.PK, SK: item.SK }
}
}));
await docClient.send(new BatchWriteCommand({
RequestItems: {
[tableName]: deleteRequests
}
}));
}
lastKey = scanResponse.LastEvaluatedKey;
} while (lastKey);
}
七、软删除模式 #
7.1 软删除概念 #
text
软删除特点:
├── 不实际删除数据
├── 标记为已删除
├── 可恢复数据
└── 保留历史记录
7.2 软删除实现 #
javascript
async function softDeleteUser(userId) {
await docClient.send(new UpdateCommand({
TableName: 'Users',
Key: { UserId: userId },
UpdateExpression: 'SET DeletedAt = :now, IsDeleted = :deleted',
ExpressionAttributeValues: {
':now': new Date().toISOString(),
':deleted': true
}
}));
}
7.3 查询时过滤软删除 #
javascript
async function getActiveUsers() {
const response = await docClient.send(new ScanCommand({
TableName: 'Users',
FilterExpression: 'attribute_not_exists(IsDeleted) OR IsDeleted = :notDeleted',
ExpressionAttributeValues: {
':notDeleted': false
}
}));
return response.Items;
}
7.4 使用GSI优化软删除查询 #
javascript
// 创建表时添加GSI
{
GlobalSecondaryIndexes: [
{
IndexName: 'ActiveUsersIndex',
KeySchema: [
{ AttributeName: 'IsDeleted', KeyType: 'HASH' }
],
Projection: { ProjectionType: 'ALL' }
}
]
}
// 查询活跃用户
await docClient.send(new QueryCommand({
TableName: 'Users',
IndexName: 'ActiveUsersIndex',
KeyConditionExpression: 'IsDeleted = :notDeleted',
ExpressionAttributeValues: {
':notDeleted': false
}
}));
八、TTL自动删除 #
8.1 启用TTL #
bash
aws dynamodb update-time-to-live \
--table-name Sessions \
--time-to-live-specification \
Enabled=true,AttributeName=ExpirationTime
8.2 写入带TTL的项目 #
javascript
await docClient.send(new PutCommand({
TableName: 'Sessions',
Item: {
SessionId: 'session123',
UserId: 'user123',
Data: { /* session data */ },
ExpirationTime: Math.floor(Date.now() / 1000) + 3600 // 1小时后过期
}
}));
8.3 TTL注意事项 #
text
TTL注意事项:
├── TTL属性值为Unix时间戳(秒)
├── 删除不是即时的(通常48小时内)
├── 不保证精确删除时间
├── 不消耗WCU
└── 适合会话、日志等临时数据
九、错误处理 #
9.1 常见错误 #
javascript
try {
await docClient.send(new DeleteCommand({
TableName: 'Users',
Key: { UserId: 'user123' },
ConditionExpression: 'Status = :status',
ExpressionAttributeValues: { ':status': 'active' }
}));
} catch (error) {
switch (error.name) {
case 'ConditionalCheckFailedException':
console.error('条件检查失败,项目未删除');
break;
case 'ProvisionedThroughputExceededException':
console.error('超过预置吞吐量');
break;
case 'ResourceNotFoundException':
console.error('表不存在');
break;
case 'ValidationException':
console.error('参数验证失败:', error.message);
break;
default:
console.error('未知错误:', error);
}
}
9.2 重试策略 #
javascript
async function deleteWithRetry(params, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await docClient.send(new DeleteCommand(params));
} catch (error) {
if (error.name === 'ProvisionedThroughputExceededException' && i < maxRetries - 1) {
await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 100));
continue;
}
throw error;
}
}
}
十、最佳实践 #
10.1 删除策略选择 #
text
策略选择:
├── 硬删除
│ ├── 不需要保留数据
│ ├── 数据隐私要求
│ └── 存储成本敏感
├── 软删除
│ ├── 需要恢复数据
│ ├── 需要历史记录
│ └── 审计要求
└── TTL
├── 自动过期
├── 会话数据
└── 日志数据
10.2 性能考虑 #
text
性能建议:
├── 使用批量删除减少请求次数
├── 合理设置删除条件
├── 避免高峰期大量删除
└── 监控删除操作
10.3 安全考虑 #
text
安全建议:
├── 使用条件删除保护数据
├── 实现软删除便于恢复
├── 记录删除操作日志
└── 定期清理软删除数据
十一、总结 #
删除操作要点:
| 操作 | 说明 | 适用场景 |
|---|---|---|
| DeleteItem | 删除单个项目 | 精确删除 |
| BatchWriteItem | 批量删除 | 大量删除 |
| 软删除 | 标记删除 | 需要恢复 |
| TTL | 自动过期 | 临时数据 |
下一步,让我们学习批量操作!
最后更新:2026-03-27