JAVA AWS 根据Dynamodb增删改查数据

前言

dynamodb是AWS的一款非关系型数据库。适用于无需频繁增删改查且关联性不强的大数据,比如某个用户的历史订单信息等。

历史订单可能不常查询但数据量很大,且只要有用户ID就可以查询出来,类似这种的可以使用非关系型数据库。

这个例子未必恰当,仅想表达不是任何情况都要使用非关系型数据库,每种数据库都有其存在的意义。(曾经因为这个被坑的很惨)

进入正题:

可进入AWS官网查看Java Dynamodb的文档,但我觉得文档写的过大过多,不太好找,所以自己记录下。

在AWS控制台创建表,创建过程中要制定分区键和排序键,若未创建排序键无法候补,只能删表重建。

Dynamodb无法分库,因此表名要清楚明了。

 

重要::虽然我很菜,写的也不够好,但我不接受任何批评,本文仅供有需要的人参考及自己记录用。

实体常用注解:映射实体和表的关系,放在getter方法上

@DynamoDBHashKey 注释分区键
@DynamoDBRangeKey 注释排序键
@DynamoDBAttribute 注释普通属性
@DynamoDBIndexHashKey 注释二级索引分区键
@DynamoDBIndexRangeKey 注释二级索引排序键
@DynamoDBIgnore 忽略某个对象或属性
// 分区键
@DynamoDBHashKey(attributeName="user_id")
public String getUserId() {
    return userId;
}

// 排序键
@DynamoDBRangeKey(attributeName="event_id")
public String getEventId() {
    return eventId;
}

// 二级索引
@DynamoDBIndexHashKey(globalSecondaryIndexName= "user_name-index", attributeName= "user_name")
public String getUserName() {
    return userName;
}

// 属性
@DynamoDBAttribute(attributeName="user_gender")
public String getUserGender() {
    return userGender;
}

// 忽略
@DynamoDBIgnore
public Student getStudent() {
    return student;
}

...

代码实现

注意::

① withKeyConditionExpression 针对分区键、排序键的查询条件中,不支持使用contains模糊查询

② withFilterExpression 针对其他字段的过滤查询条件,结合limit使用,会先查询,后分页,导致数据变少

因此Dynamodb无法在模糊查询的同时进行分页。

Service层

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBQueryExpression;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBScanExpression;
import com.amazonaws.services.dynamodbv2.datamodeling.QueryResultPage;
import com.amazonaws.services.dynamodbv2.datamodeling.ScanResultPage;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.systron.common.dao.BaseDao;
import com.systron.models.Student;
import com.systron.models.Teacher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

@Service
public class TestService {

    @Autowired
    public BaseDao baseDao;

    /**
     * Student表: 分区键student_id、二级索引student_name等
     * Teacher表: 分区键teacher_id、排序键student_id、二级索引teacher_name等
     *
     */

    /**
     * 插入数据
     */
    public void saveDemoData() {
        Student demoInfo = new Student();
        demoInfo.setStudentId("sId1");
        demoInfo.setStudentName("sName1");

        baseDao.saveItem(demoInfo);
    }

    /**
     * 更新数据
     */
    public void updateDemoData() {
        Student demoInfo = new Student();
        demoInfo.setStudentId("sId1");
        demoInfo.setStudentName("sName1");

        baseDao.updateItem(demoInfo);
    }

    /**
     * 删除数据
     */
    public void deleteDemoData() {
        Student demoInfo = new Student();
        demoInfo.setStudentId("sId1");
        demoInfo.setStudentName("sName1");

        baseDao.deleteItem(demoInfo);
    }

    /**
     * Query
     * 根据分区键查询
     */
    public Student getQueryResult() {
        Student demoInfo = (Student) baseDao.getQueryResult(Student.class, "sId1");
        System.out.println(demoInfo);
        return demoInfo;
    }
    
    /**
     * Query
     * 根据二级索引查询
     */
    public void getQueryIndexResult() {
        // 构建查询数据
        Map<String, AttributeValue> vals = new HashMap<>();
        vals.put(":v_student_name", new AttributeValue().withS("sName1"));

        DynamoDBQueryExpression<Student> exp = new DynamoDBQueryExpression<Student>()
                .withKeyConditionExpression("student_name = :v_student_name") // 查询条件
                .withIndexName("student_name-index") // 二级索引名称
                .withExpressionAttributeValues(vals) // 查询条件赋值
                .withConsistentRead(false); // 最终一致性,需设置成false

        QueryResultPage<Student> result = (QueryResultPage<Student>) baseDao.getQueryPageExpResult(Student.class, exp);

        System.out.println(result);
        // 总条数
        System.out.println("Result size ===>" + result.getResults().size());
        // 是否存在下一页
        System.out.println("Last evaluated key ===>" + result.getLastEvaluatedKey());
    }
    

    /**
     * Query 查询
     * 根据分区键、排序键查询数据
     */
    public void getQueryExpResult() {
        Map<String, AttributeValue> vals = new HashMap<String, AttributeValue>();
        vals.put(":v_teacher_id", new AttributeValue().withS("tId1"));
        vals.put(":v_student_id",new AttributeValue().withS("sId1"));

        DynamoDBQueryExpression<Teacher> queryExpression = new DynamoDBQueryExpression<Teacher>()
            .withKeyConditionExpression("teacher_id = :v_teacher_id and student_id > :v_student_id")
            .withExpressionAttributeValues(vals);

        List<Teacher> list = baseDao.getQueryExpResult(Teacher.class, queryExpression);
        System.out.println(list);
    }
    
    /**
     * Query 分页查询
     * 根据二级索引查询
     */
    public void getQueryPageExpResult() {
        // 构建查询数据
        Map<String, AttributeValue> vals = new HashMap<>();
        vals.put(":v_teacher_name", new AttributeValue().withS("tName1"));

        DynamoDBQueryExpression<Teacher> exp = new DynamoDBQueryExpression<Teacher>()
                .withKeyConditionExpression("teacher_name = :v_teacher_name") // 查询条件
                .withIndexName("teacher_name-index") // 二级索引名称
                .withExpressionAttributeValues(vals) // 查询条件赋值
                .withScanIndexForward(true)
                .withConsistentRead(false)
                .withLimit(3); // 分页条数

        // 下一页赋值
        Map<String, AttributeValue> startKey = new HashMap<>();
        startKey.put("teacher_id", new AttributeValue().withS("tId1"));
        startKey.put("student_id", new AttributeValue().withS("sId2"));
        exp.setExclusiveStartKey(startKey);

        QueryResultPage<Teacher> result = (QueryResultPage<Teacher>) baseDao.getQueryPageExpResult(Teacher.class, exp);

        // 返回结果
        List<Teacher> list = result.getResults();
        
        System.out.println("Result size ===>" + result.getResults().size());
        System.out.println("Last evaluated key ===>" + result.getLastEvaluatedKey());

    }

    /**
     * Scan 查询
     */
    public void getScanList() {
        Map<String, AttributeValue> vals = new HashMap<>();
        vals.put(":v_student_address", new AttributeValue().withS("地址1"));

        // 构建查询数据
        DynamoDBScanExpression exp = new DynamoDBScanExpression()
                .withFilterExpression("contains(student_address,:v_student_address)")
                .withExpressionAttributeValues(vals)
                .withLimit(3);

        List<Student> b = (List<Student>) baseDao.getScanResult(Student.class, exp);
    }

    /**
     * Scan分页查询
     */
    public void getScanPageList() {
        Map<String, AttributeValue> vals = new HashMap<>();
        vals.put(":v_student_address", new AttributeValue().withS("地址1"));

        DynamoDBScanExpression exp = new DynamoDBScanExpression()
                .withFilterExpression("contains(student_address,:v_student_address)")
                .withExpressionAttributeValues(vals)
                .withLimit(3);

         // 下一页赋值
        Map<String, AttributeValue> startKey = new HashMap<>();
        startKey.put("student_id", new AttributeValue().withS("sId1"));
        exp.setExclusiveStartKey(startKey);

        ScanResultPage<Student> result = baseDao.getScanPageResult(Student.class, exp);

        System.out.println("Result size ===>" + result.getResults().size());
        System.out.println("Last evaluated key ===>" + result.getLastEvaluatedKey());
    }

}

 

Dao层

import com.amazonaws.regions.Regions;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.datamodeling.*;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class BaseDao {

    static Regions region = Regions.CN_NORTHWEST_1;
    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
            .withRegion(region).build();
    static DynamoDBMapper dynamoDBMapper = new DynamoDBMapper(client);
    
    /**
     * 插入数据
     */
    public void saveItem(Object clazz) {
        try {
            dynamoDBMapper.save(clazz);
        } catch (Exception e) {
            System.err.println("插入失败:" + e.getMessage());
        }
    }
    
    /**
     * 更新数据
     */
    public void updateItem(Object clazz) {
        try {
            dynamoDBMapper.save(clazz);
        } catch (Exception e) {
            System.err.println("更新失败:" + e.getMessage());
        }
    }
    
    /**
     * 删除数据
     */
    public void deleteItem(Object clazz) {
        try {
            dynamoDBMapper.delete(clazz);
        } catch (Exception e) {
            System.err.println("删除失败:" + e.getMessage());
        }
    }
    
    /**
     * Query
     * 根据分区键查询
     */
    public Object getQueryResult(Class<?> clazz, String pk) {
        return dynamoDBMapper.load(clazz, pk);
    }
    
    /**
     * Query
     * 根据分区键、排序键查询
     */
    public <T> List<T> getQueryExpResult(Class<?> clazz, DynamoDBQueryExpression queryExp) {
        return dynamoDBMapper.query(clazz, queryExp);
    }
    
    
    /**
     * Query 分页查询
     */
    public <T> QueryResultPage getQueryPageExpResult(Class<T> clazz, DynamoDBQueryExpression queryExp) {
        return dynamoDBMapper.queryPage(clazz, queryExp);
    }
    
    /**
     * Scan 查询
     */
    public List<?> getScanResult(Class<?> clazz, DynamoDBScanExpression scanExp) {
        return dynamoDBMapper.scan(clazz, scanExp);
    }
    
    /**
     * Scan 查询  分页查询
     */
    public <T> ScanResultPage getScanPageResult(Class<T> clazz, DynamoDBScanExpression scanExp) {
        return dynamoDBMapper.scanPage(clazz, scanExp);
    }
}

 

上一篇:桶排序—leetcode164


下一篇:Azure – 对比 AWS Research Report