在Spring项目中操作Amazon DynamoDB,可通过Spring Data DynamoDB或AWS SDK for Java实现。以下是具体实现步骤和示例:

1. 项目配置

添加依赖(Maven)

<!-- AWS SDK for DynamoDB -->
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-dynamodb</artifactId>
    <version>1.12.458</version>
</dependency>

<!-- Spring Data DynamoDB -->
<dependency>
    <groupId>com.github.derjust</groupId>
    <artifactId>spring-data-dynamodb</artifactId>
    <version>5.3.0</version>
</dependency>

配置AWS凭证

application.properties中添加:

amazon.aws.accesskey=YOUR_ACCESS_KEY
amazon.aws.secretkey=YOUR_SECRET_KEY
amazon.aws.region=us-west-2  # 根据实际区域修改

2. 方式一:使用Spring Data DynamoDB(推荐)

步骤1:配置DynamoDB连接

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import org.socialsignin.spring.data.dynamodb.repository.config.EnableDynamoDBRepositories;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableDynamoDBRepositories(basePackages = "com.example.repository")
public class DynamoDBConfig {

    @Value("${amazon.aws.accesskey}")
    private String amazonAWSAccessKey;

    @Value("${amazon.aws.secretkey}")
    private String amazonAWSSecretKey;

    @Value("${amazon.aws.region}")
    private String amazonAWSRegion;

    @Bean
    public AmazonDynamoDB amazonDynamoDB() {
        return AmazonDynamoDBClientBuilder.standard()
                .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(
                        "dynamodb." + amazonAWSRegion + ".amazonaws.com", amazonAWSRegion))
                .withCredentials(new AWSStaticCredentialsProvider(
                        new BasicAWSCredentials(amazonAWSAccessKey, amazonAWSSecretKey)))
                .build();
    }
}

步骤2:定义实体类

import com.amazonaws.services.dynamodbv2.datamodeling.*;
import lombok.Data;

@Data
@DynamoDBTable(tableName = "Users")
public class User {

    @DynamoDBHashKey(attributeName = "id")
    @DynamoDBAutoGeneratedKey
    private String id;

    @DynamoDBAttribute(attributeName = "name")
    private String name;

    @DynamoDBAttribute(attributeName = "age")
    private Integer age;
}

步骤3:创建Repository接口

import org.socialsignin.spring.data.dynamodb.repository.EnableScan;
import org.springframework.data.repository.CrudRepository;

@EnableScan
public interface UserRepository extends CrudRepository<User, String> {
    // 自定义查询方法
    List<User> findByName(String name);
}

步骤4:使用Repository操作数据

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public User saveUser(User user) {
        return userRepository.save(user);
    }

    public User getUser(String id) {
        return userRepository.findById(id).orElse(null);
    }

    public List<User> findUsersByName(String name) {
        return userRepository.findByName(name);
    }

    public void deleteUser(String id) {
        userRepository.deleteById(id);
    }
}

3. 方式二:直接使用AWS SDK for Java

步骤1:注入DynamoDB客户端

@Configuration
public class DynamoDBConfig {

    @Value("${amazon.aws.accesskey}")
    private String accessKey;

    @Value("${amazon.aws.secretkey}")
    private String secretKey;

    @Value("${amazon.aws.region}")
    private String region;

    @Bean
    public AmazonDynamoDB amazonDynamoDB() {
        return AmazonDynamoDBClientBuilder.standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(
                        new BasicAWSCredentials(accessKey, secretKey)))
                .build();
    }
}

步骤2:编写服务类操作DynamoDB

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.document.*;
import com.amazonaws.services.dynamodbv2.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
public class DynamoDBService {

    private final DynamoDB dynamoDB;
    private static final String TABLE_NAME = "Users";

    @Autowired
    public DynamoDBService(AmazonDynamoDB amazonDynamoDB) {
        this.dynamoDB = new DynamoDB(amazonDynamoDB);
    }

    // 创建表(如果不存在)
    public void createTable() {
        try {
            Table table = dynamoDB.createTable(TABLE_NAME,
                    Arrays.asList(
                            new KeySchemaElement("id", KeyType.HASH)
                    ),
                    Arrays.asList(
                            new AttributeDefinition("id", ScalarAttributeType.S)
                    ),
                    new ProvisionedThroughput(10L, 10L));
            table.waitForActive();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 插入数据
    public void putItem(String id, String name, int age) {
        Table table = dynamoDB.getTable(TABLE_NAME);
        Item item = new Item()
                .withPrimaryKey("id", id)
                .withString("name", name)
                .withNumber("age", age);
        table.putItem(item);
    }

    // 查询数据
    public Item getItem(String id) {
        Table table = dynamoDB.getTable(TABLE_NAME);
        return table.getItem("id", id);
    }

    // 更新数据
    public void updateItem(String id, String name, int age) {
        Table table = dynamoDB.getTable(TABLE_NAME);
        UpdateItemSpec updateItemSpec = new UpdateItemSpec()
                .withPrimaryKey("id", id)
                .withUpdateExpression("set #n = :name, #a = :age")
                .withNameMap(new NameMap().with("#n", "name").with("#a", "age"))
                .withValueMap(new ValueMap().withString(":name", name).withNumber(":age", age))
                .withReturnValues(ReturnValue.UPDATED_NEW);
        table.updateItem(updateItemSpec);
    }

    // 删除数据
    public void deleteItem(String id) {
        Table table = dynamoDB.getTable(TABLE_NAME);
        DeleteItemSpec deleteItemSpec = new DeleteItemSpec()
                .withPrimaryKey("id", id);
        table.deleteItem(deleteItemSpec);
    }
}

4. 本地开发测试(可选)

使用DynamoDB Local进行本地测试:

@Configuration
@Profile("test")
public class DynamoDBLocalConfig extends DynamoDBConfig {

    @Override
    @Bean
    public AmazonDynamoDB amazonDynamoDB() {
        return AmazonDynamoDBClientBuilder.standard()
                .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(
                        "http://localhost:8000", "us-west-2"))
                .withCredentials(new AWSStaticCredentialsProvider(
                        new BasicAWSCredentials("test", "test")))
                .build();
    }
}

5. 注意事项

  1. 权限管理:使用IAM角色而非硬编码凭证,推荐在AWS环境中使用EC2实例角色或Lambda执行角色。
  2. 异常处理:DynamoDB操作可能抛出ResourceNotFoundExceptionProvisionedThroughputExceededException等异常,需适当处理。
  3. 性能优化
    • 使用BatchWriteItemBatchGetItem处理批量操作。
    • 合理设计表结构,避免频繁全表扫描。
  4. 分区键设计:确保数据均匀分布在多个分区,避免"热点"问题。

总结

  • Spring Data方式:适合快速开发,提供类似JPA的Repository抽象,减少样板代码。
  • AWS SDK方式:适合需要精细控制DynamoDB API的场景,灵活性更高。

根据项目规模和复杂度选择合适的实现方式,同时注意遵循AWS最佳实践确保安全性和性能。