DynamoDB写入数据 #

一、PutItem概述 #

1.1 基本概念 #

PutItem 用于向表中写入一个新项目,或替换现有项目。

text
PutItem特点:
├── 创建新项目
├── 完全替换现有项目
├── 支持条件写入
├── 支持返回旧值
└── 原子操作

1.2 与UpdateItem区别 #

操作 行为 适用场景
PutItem 完全替换项目 创建或完全替换
UpdateItem 部分更新属性 修改部分属性

二、基本写入 #

2.1 使用CLI #

bash
aws dynamodb put-item \
  --table-name Users \
  --item '{
    "UserId": {"S": "user123"},
    "Name": {"S": "John Doe"},
    "Email": {"S": "john@example.com"},
    "Age": {"N": "30"},
    "IsActive": {"BOOL": true}
  }'

2.2 使用JavaScript SDK #

javascript
const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
const { DynamoDBDocumentClient, PutCommand } = require('@aws-sdk/lib-dynamodb');

const client = new DynamoDBClient({ region: 'us-east-1' });
const docClient = DynamoDBDocumentClient.from(client);

await docClient.send(new PutCommand({
  TableName: 'Users',
  Item: {
    UserId: 'user123',
    Name: 'John Doe',
    Email: 'john@example.com',
    Age: 30,
    IsActive: true
  }
}));

2.3 使用Python SDK #

python
import boto3

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Users')

table.put_item(
    Item={
        'UserId': 'user123',
        'Name': 'John Doe',
        'Email': 'john@example.com',
        'Age': 30,
        'IsActive': True
    }
)

2.4 使用Java SDK #

java
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;

DynamoDbClient client = DynamoDbClient.create();

Map<String, AttributeValue> item = new HashMap<>();
item.put("UserId", AttributeValue.builder().s("user123").build());
item.put("Name", AttributeValue.builder().s("John Doe").build());
item.put("Email", AttributeValue.builder().s("john@example.com").build());
item.put("Age", AttributeValue.builder().n("30").build());
item.put("IsActive", AttributeValue.builder().bool(true).build());

PutItemRequest request = PutItemRequest.builder()
    .tableName("Users")
    .item(item)
    .build();

client.putItem(request);

三、条件写入 #

3.1 仅当不存在时写入 #

bash
aws dynamodb put-item \
  --table-name Users \
  --item '{
    "UserId": {"S": "user123"},
    "Name": {"S": "John Doe"}
  }' \
  --condition-expression 'attribute_not_exists(UserId)'
javascript
await docClient.send(new PutCommand({
  TableName: 'Users',
  Item: {
    UserId: 'user123',
    Name: 'John Doe'
  },
  ConditionExpression: 'attribute_not_exists(UserId)'
}));

3.2 条件检查属性值 #

javascript
await docClient.send(new PutCommand({
  TableName: 'Users',
  Item: {
    UserId: 'user123',
    Name: 'John Doe',
    Version: 1
  },
  ConditionExpression: 'attribute_not_exists(Version) OR Version < :maxVersion',
  ExpressionAttributeValues: {
    ':maxVersion': 10
  }
}));

3.3 常用条件表达式 #

javascript
// 属性不存在
'attribute_not_exists(UserId)'

// 属性存在
'attribute_exists(Email)'

// 属性值比较
'Age > :minAge'
'Status = :status'

// 属性类型检查
'attribute_type(Email, :type)'  // :type = "S"

// 字符串操作
'begins_with(Email, :prefix)'
'contains(Tags, :tag)'

// 大小检查
'size(Description) < :maxSize'

// 组合条件
'attribute_not_exists(UserId) AND Email = :email'

3.4 处理条件失败 #

javascript
try {
  await docClient.send(new PutCommand({
    TableName: 'Users',
    Item: { UserId: 'user123', Name: 'John Doe' },
    ConditionExpression: 'attribute_not_exists(UserId)'
  }));
  console.log('Item created successfully');
} catch (error) {
  if (error.name === 'ConditionalCheckFailedException') {
    console.log('Item already exists');
  } else {
    throw error;
  }
}

四、返回值配置 #

4.1 返回旧值 #

javascript
const response = await docClient.send(new PutCommand({
  TableName: 'Users',
  Item: {
    UserId: 'user123',
    Name: 'John Smith',  // 更新名字
    Email: 'john@example.com'
  },
  ReturnValues: 'ALL_OLD'  // 返回被替换的旧项目
}));

if (response.Attributes) {
  console.log('Old item:', response.Attributes);
}

4.2 返回值选项 #

选项 说明
NONE 不返回任何值(默认)
ALL_OLD 返回被替换的旧项目
UPDATED_OLD 不适用于PutItem

五、写入复杂类型 #

5.1 写入嵌套对象 #

javascript
await docClient.send(new PutCommand({
  TableName: 'Users',
  Item: {
    UserId: 'user123',
    Name: 'John Doe',
    Address: {
      Street: '123 Main St',
      City: 'Beijing',
      Country: 'China',
      ZipCode: '100000'
    },
    Contacts: {
      Email: 'john@example.com',
      Phone: '+86-138-xxxx-xxxx'
    }
  }
}));

5.2 写入列表 #

javascript
await docClient.send(new PutCommand({
  TableName: 'Products',
  Item: {
    ProductId: 'prod001',
    Name: 'iPhone 15',
    Tags: ['electronics', 'smartphone', 'apple'],
    Prices: [999, 1099, 1199],
    Specifications: [
      { Key: 'Storage', Value: '128GB' },
      { Key: 'Color', Value: 'Black' }
    ]
  }
}));

5.3 写入集合 #

javascript
await docClient.send(new PutCommand({
  TableName: 'Users',
  Item: {
    UserId: 'user123',
    Name: 'John Doe',
    Tags: new Set(['premium', 'verified', 'active']),
    Scores: new Set([95, 87, 92])
  }
}));

5.4 写入二进制数据 #

javascript
const fs = require('fs');

const imageBuffer = fs.readFileSync('image.png');

await docClient.send(new PutCommand({
  TableName: 'Files',
  Item: {
    FileId: 'file001',
    FileName: 'image.png',
    Content: imageBuffer,
    MimeType: 'image/png',
    Size: imageBuffer.length
  }
}));

六、性能优化 #

6.1 批量写入 #

对于大量写入,使用BatchWriteItem:

javascript
const { BatchWriteCommand } = require('@aws-sdk/lib-dynamodb');

const items = [
  { UserId: 'user1', Name: 'User One' },
  { UserId: 'user2', Name: 'User Two' },
  { UserId: 'user3', Name: 'User Three' }
];

const putRequests = items.map(item => ({
  PutRequest: { Item: item }
}));

await docClient.send(new BatchWriteCommand({
  RequestItems: {
    Users: putRequests
  }
}));

6.2 并行写入 #

javascript
const items = [
  { UserId: 'user1', Name: 'User One' },
  { UserId: 'user2', Name: 'User Two' },
  { UserId: 'user3', Name: 'User Three' }
];

await Promise.all(
  items.map(item => 
    docClient.send(new PutCommand({
      TableName: 'Users',
      Item: item
    }))
  )
);

6.3 写入容量规划 #

text
WCU计算:
├── 1 WCU = 1次写入(1KB)
├── 项目大小向上取整到1KB
└── 示例:
    ├── 写入500字节 = 1 WCU
    ├── 写入2.5KB = 3 WCU
    └── 写入100KB = 100 WCU

七、错误处理 #

7.1 常见错误 #

javascript
try {
  await docClient.send(new PutCommand({
    TableName: 'Users',
    Item: { UserId: 'user123', Name: 'John Doe' }
  }));
} catch (error) {
  switch (error.name) {
    case 'ConditionalCheckFailedException':
      console.error('条件检查失败');
      break;
    case 'ProvisionedThroughputExceededException':
      console.error('超过预置吞吐量');
      break;
    case 'ResourceNotFoundException':
      console.error('表不存在');
      break;
    case 'ItemCollectionSizeLimitExceededException':
      console.error('项目集合大小超限');
      break;
    case 'ValidationException':
      console.error('参数验证失败:', error.message);
      break;
    default:
      console.error('未知错误:', error);
  }
}

7.2 重试策略 #

javascript
async function putWithRetry(params, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await docClient.send(new PutCommand(params));
    } catch (error) {
      if (error.name === 'ProvisionedThroughputExceededException' && i < maxRetries - 1) {
        await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 100));
        continue;
      }
      throw error;
    }
  }
}

八、最佳实践 #

8.1 项目大小优化 #

text
优化建议:
├── 避免存储不必要的数据
├── 压缩大文本和二进制数据
├── 使用S3存储大文件
└── 项目大小控制在400KB以内

8.2 条件写入使用场景 #

text
适用场景:
├── 防止重复创建
├── 乐观锁实现
├── 唯一性约束
└── 业务规则验证

8.3 批量写入限制 #

text
BatchWriteItem限制:
├── 每批最多25个操作
├── 每批最大16MB数据
├── 每个项目最大400KB
└── 不支持条件表达式

九、完整示例 #

9.1 用户注册示例 #

javascript
async function registerUser(userData) {
  const { userId, email, name, password } = userData;
  
  try {
    await docClient.send(new PutCommand({
      TableName: 'Users',
      Item: {
        UserId: userId,
        Email: email,
        Name: name,
        PasswordHash: hashPassword(password),
        CreatedAt: new Date().toISOString(),
        IsActive: true,
        Version: 1
      },
      ConditionExpression: 'attribute_not_exists(UserId)',
      ReturnValues: 'ALL_OLD'
    }));
    
    return { success: true, userId };
  } catch (error) {
    if (error.name === 'ConditionalCheckFailedException') {
      return { success: false, error: 'User already exists' };
    }
    throw error;
  }
}

9.2 带版本控制的写入 #

javascript
async function updateUserWithVersion(userId, updates, expectedVersion) {
  try {
    const response = await docClient.send(new PutCommand({
      TableName: 'Users',
      Item: {
        UserId: userId,
        ...updates,
        Version: expectedVersion + 1,
        UpdatedAt: new Date().toISOString()
      },
      ConditionExpression: 'Version = :expectedVersion',
      ExpressionAttributeValues: {
        ':expectedVersion': expectedVersion
      }
    }));
    
    return { success: true };
  } catch (error) {
    if (error.name === 'ConditionalCheckFailedException') {
      return { success: false, error: 'Version conflict' };
    }
    throw error;
  }
}

十、总结 #

PutItem要点:

特性 说明
基本功能 创建或替换项目
条件写入 支持条件表达式
返回值 可返回旧项目
原子性 单个项目原子操作
大小限制 最大400KB

下一步,让我们学习更新数据!

最后更新:2026-03-27