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 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());
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);