3. AWS DynamoDB实战之CRUD

基表抽象

 在 2. AWS DynamoDB实战之表的设计 一文中,详细介绍了如何设计dto model以及dynamodb的表,仔细观察我们的三个dto,它们具有一些共同点:

  • 都有pk和sk的getter和setter
  • item的唯一标识符由pk和sk构成

综合上述特点,我们抽象出一个dto mode的基类AbstractDto:

  • AbstractDto是一个抽象类
  • 包含四个抽象方法,分别为pk和sk的getter和setter
  • 包含一个用于获取item唯一标识符的方法,返回的唯一标识符格式为:  pk#sk
package com.jessica.dynamodb.favorite.dto;

public abstract class AbstractDto {
	public abstract String getPk();

	public abstract void setPk(String hashKey);

	public abstract String getSk();

	public abstract void setSk(String rangeKey);

	/**
	 * return composite keys as unique key string
	 * 
	 * @return
	 */
	public String getCompositeKey() {
		return String.join("#", getPk(), getSk());
	}
}

添加了AbstractDto以后,其他所有的Dto都需要继承该类:

package com.jessica.dynamodb.favorite.dto;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIgnore;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIndexRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import com.jessica.dynamodb.constant.DynamoDBConstant;
import com.jessica.dynamodb.utils.KeyGenerator;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DynamoDBTable(tableName = "develop.Favorite")
@EqualsAndHashCode(callSuper = false)
public class TagDto extends AbstractDto {
	private static final String DTO_NAME = "Tag";

	@DynamoDBIgnore
	private String userId;
	@DynamoDBIgnore
	private String tagId;
	@DynamoDBAttribute
	private String tagName;
	@DynamoDBAttribute
	private long createTime;
	@DynamoDBAttribute
	private long lastAccessTime;

	@DynamoDBHashKey
	@Override
	public String getPk() {
		return KeyGenerator.createHashKey(DTO_NAME, userId);
	}

	@Override
	public void setPk(String hashKey) {
		String[] keys = KeyGenerator.parseHashKey(DTO_NAME, hashKey);
		this.userId = keys[0];
	}

	@DynamoDBRangeKey
	@Override
	public String getSk() {
		return KeyGenerator.createRangeKey(tagId);
	}

	@Override
	public void setSk(String rangeKey) {
		String[] keys = KeyGenerator.parseRangeKey(rangeKey);
		this.tagId = keys[0];
	}

	@DynamoDBIndexRangeKey(localSecondaryIndexName = DynamoDBConstant.LSI_ONE_NAME)
	public String getLsiOneSk() {
		return KeyGenerator.createRangeKey(tagName);
	}

	public void setLsiOneSk(String lsiOneSk) {
	}

	@DynamoDBIndexRangeKey(localSecondaryIndexName = DynamoDBConstant.LSI_TWO_NAME)
	public String getLsiTwoSk() {
		return KeyGenerator.createRangeKey(String.valueOf(createTime), tagId);
	}

	public void setLsiTwoSk(String lsiTwoSk) {
	}

	@DynamoDBIndexRangeKey(localSecondaryIndexName = DynamoDBConstant.LSI_THREE_NAME)
	public String getLsiThreeSk() {
		return KeyGenerator.createRangeKey(String.valueOf(lastAccessTime), tagId);
	}

	public void setLsiThreeSk(String lsiThreeSk) {
	}

}
package com.jessica.dynamodb.favorite.dto;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIgnore;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIndexHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIndexRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTypeConvertedEnum;
import com.jessica.dynamodb.constant.DynamoDBConstant;
import com.jessica.dynamodb.utils.KeyGenerator;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DynamoDBTable(tableName = "develop.Favorite")
@EqualsAndHashCode(callSuper = false)
public class FavoriteDataDto extends AbstractDto {
	private static final String DTO_NAME = "FavoriteData";

	@DynamoDBIgnore
	private String userId;
	@DynamoDBIgnore
	private String dataId;
	@DynamoDBAttribute
	private String creatorId;
	@DynamoDBAttribute
	private String title;
	@DynamoDBAttribute
	private String thumbnailUrl;
	@DynamoDBAttribute
	private String contentUrl;
	@DynamoDBTypeConvertedEnum
	@DynamoDBAttribute
	private FavoriteDataType dataType;
	@DynamoDBAttribute
	private String clipTime;

	@DynamoDBHashKey
	@Override
	public String getPk() {
		return KeyGenerator.createHashKey(DTO_NAME, userId);
	}

	@Override
	public void setPk(String hashKey) {
		String[] keys = KeyGenerator.parseHashKey(DTO_NAME, hashKey);
		this.userId = keys[0];
	}

	@DynamoDBRangeKey
	@Override
	public String getSk() {
		return KeyGenerator.createRangeKey(dataId);
	}

	@Override
	public void setSk(String rangeKey) {
		String[] keys = KeyGenerator.parseRangeKey(rangeKey);
		this.dataId = keys[0];
	}

	@DynamoDBIndexHashKey(globalSecondaryIndexName = DynamoDBConstant.GSI_ONE_NAME)
	public String getGsiOnePk() {
		return KeyGenerator.createHashKey(DTO_NAME, userId, dataType.getValue());
	}

	public void setGsiOnePk(String hashKey) {
	}

	@DynamoDBIndexRangeKey(globalSecondaryIndexName = DynamoDBConstant.GSI_ONE_NAME)
	public String getGsiOneSk() {
		return KeyGenerator.createRangeKey(clipTime, dataId);
	}

	public void setGsiOneSk(String rangeKey) {
	}
}
package com.jessica.dynamodb.favorite.dto;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIgnore;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIndexHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIndexRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTypeConvertedEnum;
import com.jessica.dynamodb.constant.DynamoDBConstant;
import com.jessica.dynamodb.utils.KeyGenerator;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DynamoDBTable(tableName = "develop.Favorite")
@EqualsAndHashCode(callSuper = false)
public class FavoriteDataTagDto extends AbstractDto {
	private static final String DTO_NAME = "FavoriteDataTag";

	@DynamoDBIgnore
	private String userId;
	@DynamoDBIgnore
	private String dataId;
	@DynamoDBIgnore
	private String tagId;
	@DynamoDBAttribute
	private String clipTime;
	@DynamoDBTypeConvertedEnum
	@DynamoDBAttribute
	private FavoriteDataType dataType;

	@DynamoDBHashKey
	@Override
	public String getPk() {
		return KeyGenerator.createHashKey(DTO_NAME, userId, dataId);
	}

	@Override
	public void setPk(String hashKey) {
		String[] keys = KeyGenerator.parseHashKey(DTO_NAME, hashKey);
		this.userId = keys[0];
		this.dataId = keys[1];
	}

	@DynamoDBRangeKey
	@Override
	public String getSk() {
		return KeyGenerator.createRangeKey(tagId);
	}

	@Override
	public void setSk(String rangeKey) {
		String[] keys = KeyGenerator.parseRangeKey(rangeKey);
		this.tagId = keys[0];
	}

	@DynamoDBIndexHashKey(globalSecondaryIndexName = DynamoDBConstant.GSI_ONE_NAME)
	public String getGsiOnePk() {
		return KeyGenerator.createHashKey(DTO_NAME, userId, tagId);
	}

	public void setGsiOnePk(String hashKey) {
	}

	@DynamoDBIndexRangeKey(globalSecondaryIndexName = DynamoDBConstant.GSI_ONE_NAME)
	public String getGsiOneSk() {
		return KeyGenerator.createRangeKey(clipTime, dataId);
	}

	public void setGsiOneSk(String rangeKey) {
	}

	@DynamoDBIndexHashKey(globalSecondaryIndexName = DynamoDBConstant.GSI_TWO_NAME)
	public String getGsiTwoPk() {
		return KeyGenerator.createHashKey(DTO_NAME, userId, tagId, dataType.getValue());
	}

	public void setGsiTwoPk(String hashKey) {
	}

	@DynamoDBIndexRangeKey(globalSecondaryIndexName = DynamoDBConstant.GSI_TWO_NAME)
	public String getGsiTwoSk() {
		return KeyGenerator.createRangeKey(clipTime, dataId);
	}

	public void setGsiTwoSk(String rangeKey) {
	}
}

通用接口抽象

一般来讲,每个dto model都会对应一个dao,用于对该dto进行crud操作.实际实现过程中发现一些基本的crud操作的代码是完全一样的,因此我们也实现一个通用接口来进行这些基本的crud操作.

package com.jessica.dynamodb.favorite.dao;

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

import com.jessica.dynamodb.favorite.data.LazyLoadResult;

public interface BasicDao<T> {
	/**
	 * create or update dto
	 * 
	 * @param dto
	 */
	void save(T dto);

	/**
	 * load dto
	 * 
	 * @param keyDto, pk and sk related fields must set
	 * @return
	 */
	T load(T keyDto);

	/**
	 * delete dto
	 * 
	 * @param keyDto, pk and sk related fields must set
	 */
	void delete(T keyDto);

	/**
	 * create or update dtos
	 * 
	 * @param dtos
	 */
	void batchSave(List<T> dtos);

	/**
	 * load dtos, result list sequence may not be same with keyDtos
	 * 
	 * @param keyDtos, pk and sk related fields must set
	 * @return
	 */
	List<T> batchLoad(List<T> keyDtos);

	/**
	 * load dto map
	 * 
	 * @param keyDtos, pk and sk related fields must set
	 * @return key is pk#sk
	 */
	Map<String, T> batchLoadMap(List<T> keyDtos);

	/**
	 * delete dtos
	 * 
	 * @param keyDtos, pk and sk related fields must set
	 * @return
	 */
	void batchDelete(List<T> keyDtos);

	/**
	 * query with pk in given order
	 * 
	 * @param clazz
	 * @param hashKeyDto
	 * @param asc
	 * @param lastLoadSk
	 * @param size
	 * @return
	 */
	LazyLoadResult<T> query(Class<T> clazz, T hashKeyDto, boolean asc, String lastLoadSk, Integer size);

	/**
	 * query index with pk in given order
	 * 
	 * @param clazz
	 * @param indexName
	 * @param indexSkName
	 * @param hashKeyDto
	 * @param asc
	 * @param lastLoadSk
	 * @param size
	 * @return
	 */
	LazyLoadResult<T> queryIndex(Class<T> clazz, String indexName, String indexSkName, T hashKeyDto, boolean asc,
			String lastLoadSk, Integer size);
}
package com.jessica.dynamodb.favorite.dao.impl;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBQueryExpression;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
import com.amazonaws.services.dynamodbv2.model.Condition;
import com.jessica.dynamodb.constant.DynamoDBConstant;
import com.jessica.dynamodb.favorite.dao.BasicDao;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.AbstractDto;

public class BasicDaoImpl<T extends AbstractDto> implements BasicDao<T> {
	protected DynamoDBMapper dynamoDBMapper = new DynamoDBMapper(AmazonDynamoDBClientBuilder.standard().build());

	@Override
	public void save(T dto) {
		this.dynamoDBMapper.save(dto);
	}

	@Override
	public T load(T keyDto) {
		return this.dynamoDBMapper.load(keyDto);
	}

	@Override
	public void delete(T keyDto) {
		this.dynamoDBMapper.delete(keyDto);
	}

	@Override
	public void batchSave(List<T> dtos) {
		this.dynamoDBMapper.batchSave(dtos);
	}

	@Override
	public List<T> batchLoad(List<T> keyDtos) {
		return this.dynamoDBMapper.batchLoad(keyDtos).values().stream().flatMap(Collection::stream)
				.map(object -> (T) object).collect(Collectors.toList());
	}

	@Override
	public Map<String, T> batchLoadMap(List<T> keyDtos) {
		return this.batchLoad(keyDtos).stream()
				.collect(Collectors.toMap(t -> ((AbstractDto) t).getCompositeKey(), Function.identity()));
	}

	@Override
	public void batchDelete(List<T> keyDtos) {
		this.dynamoDBMapper.batchDelete(keyDtos);
	}

	@Override
	public LazyLoadResult<T> query(Class<T> clazz, T hashKeyDto, boolean asc, String lastLoadSk, Integer size) {
		DynamoDBQueryExpression<T> queryExpression = new DynamoDBQueryExpression<T>().withHashKeyValues(hashKeyDto)
				.withScanIndexForward(asc);
		if (lastLoadSk != null) {
			Condition rangeCondition = new Condition()
					.withComparisonOperator(asc ? ComparisonOperator.GT : ComparisonOperator.LT)
					.withAttributeValueList(new AttributeValue(lastLoadSk));
			queryExpression.withRangeKeyCondition(DynamoDBConstant.RANGE_KEY, rangeCondition);
		}

		List<T> dtos;
		boolean hasLimit = size != null && size > 0;
		if (hasLimit) {
			queryExpression.setLimit(size);
			dtos = this.dynamoDBMapper.queryPage(clazz, queryExpression).getResults();
		} else {
			dtos = this.dynamoDBMapper.query(clazz, queryExpression);
		}

		if (dtos.size() == 0) {
			return new LazyLoadResult<>(new ArrayList<>(), false, null);
		}
		return new LazyLoadResult<>(dtos, hasLimit ? dtos.size() == size : false, dtos.get(dtos.size() - 1).getSk());
	}

	@Override
	public LazyLoadResult<T> queryIndex(Class<T> clazz, String indexName, String indexSkName, T hashKeyDto, boolean asc,
			String lastLoadSk, Integer size) {
		DynamoDBQueryExpression<T> queryExpression = new DynamoDBQueryExpression<T>().withIndexName(indexName)
				.withHashKeyValues(hashKeyDto).withScanIndexForward(asc);
		if (lastLoadSk != null) {
			Condition rangeCondition = new Condition()
					.withComparisonOperator(asc ? ComparisonOperator.GT : ComparisonOperator.LT)
					.withAttributeValueList(new AttributeValue(lastLoadSk));
			queryExpression.withRangeKeyCondition(indexSkName, rangeCondition);
		}

		List<T> dtos;
		boolean hasLimit = size != null && size > 0;
		if (hasLimit) {
			queryExpression.setLimit(size);
			dtos = this.dynamoDBMapper.queryPage(clazz, queryExpression).getResults();
		} else {
			dtos = this.dynamoDBMapper.query(clazz, queryExpression);
		}

		if (dtos.size() == 0) {
			return new LazyLoadResult<>(new ArrayList<>(), false, null);
		}
		T lastLoadDto = dtos.get(dtos.size() - 1);
		try {
			Method method = clazz.getMethod("get" + upperCaseFirstLatter(indexSkName));
			return new LazyLoadResult<T>(dtos, hasLimit ? dtos.size() == size : false,
					(String) method.invoke(lastLoadDto));
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	private String upperCaseFirstLatter(String str) {
		char[] strChar = str.toCharArray();
		strChar[0] -= 32;
		return String.valueOf(strChar);
	}
}

实现了BasicDao之后,我们通过编写JUnit test来对实现类进行测试:

pom文件中添加dependency:

 <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.12</version>
   <scope>test</scope>
 </dependency>

测试类:

package com.jessica.dynamodb.favorite.dao;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.junit.Test;

import com.jessica.dynamodb.constant.DynamoDBConstant;
import com.jessica.dynamodb.favorite.dao.impl.BasicDaoImpl;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.TagDto;

public class BasicDaoImplTest {

	BasicDao<TagDto> basicDao = new BasicDaoImpl<>();

	@Test
	public void testSaveLoadDelete() {
		// prepare data
		String userId = "userId1";
		String tagId = UUID.randomUUID().toString();
		String tagName = "firstTag";
		Date now = new Date();
		TagDto newTagDto = TagDto.builder().userId(userId).tagId(tagId).tagName(tagName).createTime(now.getTime())
				.lastAccessTime(now.getTime()).build();
		// run test
		basicDao.save(newTagDto);
		TagDto loadedDto = basicDao.load(newTagDto);
		assertNotNull(loadedDto);

		// clean data
		basicDao.delete(newTagDto);
		loadedDto = basicDao.load(newTagDto);
		assertNull(loadedDto);
	}

	@Test
	public void testBatchSaveLoadDelete() {
		// prepare data
		String userId1 = "userId1";
		String tagId1 = UUID.randomUUID().toString();
		String tagName1 = "firstTag";
		Date date1 = new Date();
		String userId2 = "userId2";
		String tagId2 = UUID.randomUUID().toString();
		String tagName2 = "secondTag";
		Date date2 = new Date();
		TagDto newTagDto1 = TagDto.builder().userId(userId1).tagId(tagId1).tagName(tagName1).createTime(date1.getTime())
				.lastAccessTime(date1.getTime()).build();
		TagDto newTagDto2 = TagDto.builder().userId(userId2).tagId(tagId2).tagName(tagName2).createTime(date2.getTime())
				.lastAccessTime(date2.getTime()).build();
		List<TagDto> dtos = Arrays.asList(newTagDto1, newTagDto2);
		basicDao.batchSave(dtos);

		// run test
		List<TagDto> loadedDtos = basicDao.batchLoad(dtos);
		assertEquals(2, loadedDtos.size());

		// clean data
		basicDao.batchDelete(dtos);

		// run test
		loadedDtos = basicDao.batchLoad(dtos);
		assertEquals(0, loadedDtos.size());
	}

	@Test
	public void testQuery() {
		// prepare data
		String userId1 = "userId1";
		String tagId1 = "firstTag";
		String tagName1 = "firstTag";
		Date date = new Date();
		String tagId2 = "secondTag";
		String tagName2 = "secondTag";
		String tagId3 = "thirdTag";
		String tagName3 = "thirdTag";
		String tagId4 = "fouthTag";
		String tagName4 = "fouthTag";
		String userId2 = "userId2";
		String tagId5 = "fifthTag";
		String tagName5 = "fifthTag";
		TagDto newTagDto1 = TagDto.builder().userId(userId1).tagId(tagId1).tagName(tagName1)
				.createTime(date.getTime() - 10000).lastAccessTime(date.getTime() - 10000).build();
		TagDto newTagDto2 = TagDto.builder().userId(userId1).tagId(tagId2).tagName(tagName2)
				.createTime(date.getTime() - 5000).lastAccessTime(date.getTime() - 5000).build();
		TagDto newTagDto3 = TagDto.builder().userId(userId1).tagId(tagId3).tagName(tagName3)
				.createTime(date.getTime() - 1000).lastAccessTime(date.getTime() - 1000).build();
		TagDto newTagDto4 = TagDto.builder().userId(userId1).tagId(tagId4).tagName(tagName4).createTime(date.getTime())
				.lastAccessTime(date.getTime()).build();
		TagDto newTagDto5 = TagDto.builder().userId(userId2).tagId(tagId5).tagName(tagName5).createTime(date.getTime())
				.lastAccessTime(date.getTime()).build();
		List<TagDto> dtos = Arrays.asList(newTagDto1, newTagDto2, newTagDto3, newTagDto4, newTagDto5);
		basicDao.batchSave(dtos);

		try {
			// test sk desc order with size
			LazyLoadResult<TagDto> lazyLoadResult = basicDao.query(TagDto.class, newTagDto1, false, null, 2);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			lazyLoadResult = basicDao.query(TagDto.class, newTagDto1, false,
					lazyLoadResult.getLoadedDtos().get(1).getSk(), 3);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(1).getTagId());

			// test sk aes order with size
			lazyLoadResult = basicDao.query(TagDto.class, newTagDto1, true, null, 2);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			lazyLoadResult = basicDao.query(TagDto.class, newTagDto1, true,
					lazyLoadResult.getLoadedDtos().get(1).getSk(), 3);
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(1).getTagId());

			// test sk aes order without size
			lazyLoadResult = basicDao.query(TagDto.class, newTagDto1, true, null, null);
			assertEquals(4, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(3).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(3).getTagId());

			lazyLoadResult = basicDao.query(TagDto.class, newTagDto1, true, newTagDto4.getSk(), null);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(1).getTagId());

			// test sk desc order without size
			lazyLoadResult = basicDao.query(TagDto.class, newTagDto1, false, null, null);
			assertEquals(4, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(3).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(3).getTagId());

			lazyLoadResult = basicDao.query(TagDto.class, newTagDto1, false, newTagDto3.getSk(), null);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(2).getTagId());
		} catch (Exception e) {
			throw e;
		} finally {
			// clean data
			basicDao.batchDelete(dtos);
		}
	}

	@Test
	public void testQueryIndex() {
		// prepare data
		String userId1 = "userId1";
		String tagId1 = UUID.randomUUID().toString();
		String tagName1 = "firstTag";
		Date date = new Date();
		String tagId2 = UUID.randomUUID().toString();
		String tagName2 = "secondTag";
		String tagId3 = UUID.randomUUID().toString();
		String tagName3 = "thirdTag";
		String tagId4 = UUID.randomUUID().toString();
		String tagName4 = "fouthTag";
		TagDto newTagDto1 = TagDto.builder().userId(userId1).tagId(tagId1).tagName(tagName1)
				.createTime(date.getTime() - 10000).lastAccessTime(date.getTime() - 10000).build();
		basicDao.save(newTagDto1);
		TagDto newTagDto2 = TagDto.builder().userId(userId1).tagId(tagId2).tagName(tagName2)
				.createTime(date.getTime() - 5000).lastAccessTime(date.getTime() - 5000).build();
		basicDao.save(newTagDto2);
		TagDto newTagDto3 = TagDto.builder().userId(userId1).tagId(tagId3).tagName(tagName3)
				.createTime(date.getTime() - 1000).lastAccessTime(date.getTime() - 1000).build();
		basicDao.save(newTagDto3);
		TagDto newTagDto4 = TagDto.builder().userId(userId1).tagId(tagId4).tagName(tagName4).createTime(date.getTime())
				.lastAccessTime(date.getTime()).build();
		List<TagDto> dtos = Arrays.asList(newTagDto1, newTagDto2, newTagDto3, newTagDto4);
		basicDao.batchSave(dtos);
		try {
			// test tag name desc order
			LazyLoadResult<TagDto> lazyLoadResult = basicDao.queryIndex(TagDto.class, DynamoDBConstant.LSI_ONE_NAME,
					DynamoDBConstant.LSI_ONE_RANGE_KEY, false, TagDto.builder().userId(userId1).build(), false, null,
					3);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			lazyLoadResult = basicDao.queryIndex(TagDto.class, DynamoDBConstant.LSI_ONE_NAME,
					DynamoDBConstant.LSI_ONE_RANGE_KEY, false, TagDto.builder().userId(userId1).build(), false,
					lazyLoadResult.getLastLoadPos(), 3);
			assertEquals(1, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());

			// test load all
			lazyLoadResult = basicDao.queryIndex(TagDto.class, DynamoDBConstant.LSI_ONE_NAME,
					DynamoDBConstant.LSI_ONE_RANGE_KEY, false, TagDto.builder().userId(userId1).build(), false, null,
					null);
			assertEquals(4, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(3).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(3).getTagId());

			// test tag name aes order
			lazyLoadResult = basicDao.queryIndex(TagDto.class, DynamoDBConstant.LSI_ONE_NAME,
					DynamoDBConstant.LSI_ONE_RANGE_KEY, false, TagDto.builder().userId(userId1).build(), true, null, 3);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			lazyLoadResult = basicDao.queryIndex(TagDto.class, DynamoDBConstant.LSI_ONE_NAME,
					DynamoDBConstant.LSI_ONE_RANGE_KEY, false, TagDto.builder().userId(userId1).build(), true,
					lazyLoadResult.getLastLoadPos(), 3);
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(1, lazyLoadResult.getLoadedDtos().size());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(0).getTagId());
		} catch (Exception e) {
			throw e;
		} finally {
			// clean data
			basicDao.batchDelete(dtos);
		}
	}
}

实现TagDao

根据之前的分析,除了基本的crud操作之后,TagDao还需要支持获取某个user创建的所有tag,返回结果可以有三种排序方式:

  • 按照tag创建的时间进行排序
  • 按照tag的名称进行排序
  • 按照tag的最近访问时间进行排序

因此只需要在TagDao实现上述三种排序方式的查询即可.

package com.jessica.dynamodb.favorite.dao;

import com.jessica.dynamodb.constant.TagSortField;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.TagDto;

public interface TagDao extends BasicDao<TagDto> {
	/**
	 * 
	 * @param userId
	 * @param tagSortField
	 * @param lastLoadSk
	 * @param size
	 * @param asc
	 * @return
	 */
	LazyLoadResult<TagDto> getTagsByUserId(String userId, TagSortField tagSortField, String lastLoadSk, Integer size,
			boolean asc);
}
package com.jessica.dynamodb.favorite.dao.impl;

import com.jessica.dynamodb.constant.TagSortField;
import com.jessica.dynamodb.favorite.dao.TagDao;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.TagDto;

public class TagDaoImpl extends BasicDaoImpl<TagDto> implements TagDao {

	@Override
	public LazyLoadResult<TagDto> getTagsByUserId(String userId, TagSortField tagSortField, String lastLoadSk,
			Integer size, boolean asc) {
		return this.queryIndex(TagDto.class, tagSortField.getLsiName(), tagSortField.getLsiSkName(),
				TagDto.builder().userId(userId).build(), asc, lastLoadSk, size);
	}
}

同样,我们通过编写JUnit test来对实现类进行测试,也可以直接写个main方法来测试:

package com.jessica.dynamodb.favorite.dao;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.junit.Test;

import com.jessica.dynamodb.constant.TagSortField;
import com.jessica.dynamodb.favorite.dao.impl.TagDaoImpl;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.TagDto;

public class TagDaoImplTest {

	TagDao tagDao = new TagDaoImpl();

	@Test
	public void testGetTagsByUserId() {
		// prepare data
		String userId1 = "userId1";
		String tagId1 = UUID.randomUUID().toString();
		String tagName1 = "firstTag";
		Date date = new Date();
		String tagId2 = UUID.randomUUID().toString();
		String tagName2 = "secondTag";
		String tagId3 = UUID.randomUUID().toString();
		String tagName3 = "thirdTag";
		String tagId4 = UUID.randomUUID().toString();
		String tagName4 = "fouthTag";
		TagDto newTagDto1 = TagDto.builder().userId(userId1).tagId(tagId1).tagName(tagName1)
				.createTime(date.getTime() - 10000).lastAccessTime(date.getTime() - 10000).build();
		tagDao.save(newTagDto1);
		TagDto newTagDto2 = TagDto.builder().userId(userId1).tagId(tagId2).tagName(tagName2)
				.createTime(date.getTime() - 5000).lastAccessTime(date.getTime() - 5000).build();
		tagDao.save(newTagDto2);
		TagDto newTagDto3 = TagDto.builder().userId(userId1).tagId(tagId3).tagName(tagName3)
				.createTime(date.getTime() - 1000).lastAccessTime(date.getTime() - 1000).build();
		tagDao.save(newTagDto3);
		TagDto newTagDto4 = TagDto.builder().userId(userId1).tagId(tagId4).tagName(tagName4).createTime(date.getTime())
				.lastAccessTime(date.getTime()).build();
		List<TagDto> dtos = Arrays.asList(newTagDto1, newTagDto2, newTagDto3, newTagDto4);
		tagDao.batchSave(dtos);
		try {

			// test tag name desc order
			LazyLoadResult<TagDto> lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.TAG_NAME, null, 3,
					false);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.TAG_NAME, lazyLoadResult.getLastLoadPos(), 3,
					false);
			assertEquals(1, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());

			// test tag name aes order
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.TAG_NAME, null, 3, true);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.TAG_NAME, lazyLoadResult.getLastLoadPos(), 3,
					true);
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(1, lazyLoadResult.getLoadedDtos().size());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(0).getTagId());

			// test create time desc order
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.CREATE_TIME, null, 3, false);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.CREATE_TIME, lazyLoadResult.getLastLoadPos(),
					3, false);
			assertEquals(1, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());

			// test create time aes order
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.CREATE_TIME, null, 3, true);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.CREATE_TIME, lazyLoadResult.getLastLoadPos(),
					3, true);
			assertEquals(1, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(0).getTagId());

			// test last access time desc order
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.LAST_ACCESS_TIME, null, 3, false);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.LAST_ACCESS_TIME,
					lazyLoadResult.getLastLoadPos(), 3, false);
			assertEquals(1, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());

			// test last access time aes order
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.LAST_ACCESS_TIME, null, 3, true);
			assertEquals(3, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId1, lazyLoadResult.getLoadedDtos().get(0).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(tagId2, lazyLoadResult.getLoadedDtos().get(1).getTagId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(tagId3, lazyLoadResult.getLoadedDtos().get(2).getTagId());
			lazyLoadResult = tagDao.getTagsByUserId(userId1, TagSortField.LAST_ACCESS_TIME,
					lazyLoadResult.getLastLoadPos(), 3, true);
			assertEquals(1, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(tagId4, lazyLoadResult.getLoadedDtos().get(0).getTagId());
		} catch (Exception e) {
			throw e;
		} finally {
			// clean data
			tagDao.batchDelete(dtos);
		}
	}
}

实现FavoriteDataDao

根据需求,除了基本的crud操作之外,FavoriteDataDto有两个方法需要实现:

  • 获取用户收藏的所有数据,并按收藏时间降序排序,只需要以userId作为hashKey进行query操作即可,已经在BasicDao中实现
  • 获取所有某种特定类型的收藏数据,并按收藏时间降序排序,所以只需要实现这一个方法,以userId&type作为hashKey,对Global Secondary Index进行query操作即可
package com.jessica.dynamodb.favorite.dao;

import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.FavoriteDataDto;
import com.jessica.dynamodb.favorite.dto.FavoriteDataType;

public interface FavoriteDataDao extends BasicDao<FavoriteDataDto> {
	/**
	 * get data for userId sort by dataId
	 * 
	 * @param userId
	 * @param lastLoadSk
	 * @param size
	 * @param asc
	 * @return
	 */
	LazyLoadResult<FavoriteDataDto> getFavoriteDataSortByDataId(String userId, String lastLoadSk, Integer size,
			boolean asc);

	/**
	 * get data for userId sort by data create time
	 * 
	 * @param userId
	 * @param lastLoadSk
	 * @param size
	 * @param asc
	 * @return
	 */
	LazyLoadResult<FavoriteDataDto> getFavoriteDataSortByCreateTime(String userId, String lastLoadSk, Integer size,
			boolean asc);

	/**
	 * get data for userId with given type
	 * 
	 * @param userId
	 * @param dataType
	 * @param lastLoadSk
	 * @param size
	 * @param asc
	 * @return
	 */
	LazyLoadResult<FavoriteDataDto> getFavoriteData(String userId, FavoriteDataType dataType, String lastLoadSk,
			Integer size, boolean asc);
}
package com.jessica.dynamodb.favorite.dao.impl;

import com.jessica.dynamodb.constant.DynamoDBConstant;
import com.jessica.dynamodb.favorite.dao.FavoriteDataDao;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.FavoriteDataDto;
import com.jessica.dynamodb.favorite.dto.FavoriteDataType;

public class FavoriteDataDaoImpl extends BasicDaoImpl<FavoriteDataDto> implements FavoriteDataDao {

	@Override
	public LazyLoadResult<FavoriteDataDto> getFavoriteDataSortByDataId(String userId, String lastLoadSk, Integer size,
			boolean asc) {
		return this.query(FavoriteDataDto.class, FavoriteDataDto.builder().userId(userId).build(), asc, lastLoadSk,
				size);
	}

	@Override
	public LazyLoadResult<FavoriteDataDto> getFavoriteData(String userId, FavoriteDataType dataType, String lastLoadSk,
			Integer size, boolean asc) {
		return this.queryIndex(FavoriteDataDto.class, DynamoDBConstant.GSI_ONE_NAME, DynamoDBConstant.GSI_ONE_RANGE_KEY,
				true, FavoriteDataDto.builder().userId(userId).dataType(dataType).build(), asc, lastLoadSk, size);
	}

	@Override
	public LazyLoadResult<FavoriteDataDto> getFavoriteDataSortByCreateTime(String userId, String lastLoadSk,
			Integer size, boolean asc) {
		return this.queryIndex(FavoriteDataDto.class, DynamoDBConstant.LSI_ONE_NAME, DynamoDBConstant.LSI_ONE_RANGE_KEY,
				false, FavoriteDataDto.builder().userId(userId).build(), asc, lastLoadSk, size);
	}
}

测试类

package com.jessica.dynamodb.favorite.dao;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.junit.Test;

import com.jessica.dynamodb.favorite.dao.impl.FavoriteDataDaoImpl;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.FavoriteDataDto;
import com.jessica.dynamodb.favorite.dto.FavoriteDataType;

public class FavoriteDataDaoImplTest {
	private FavoriteDataDao favoriteDataDao = new FavoriteDataDaoImpl();
	private String userId1 = "userId1";
	private String userId2 = "userId2";
	private String dataId1 = "dataId1";
	private String dataId2 = "dataId2";
	private String dataId3 = "dataId3";
	private String dataId4 = "dataId4";
	private String dataId5 = "dataId5";
	private String dataId6 = "dataId6";
	private FavoriteDataType dataType1 = FavoriteDataType.FILE;
	private FavoriteDataType dataType2 = FavoriteDataType.IMAGE;
	private Date date = new Date();

	@Test
	public void testGetFavoriteDataByUserIdAndType() {
		// prepare data
		List<FavoriteDataDto> dtos = this.prepareDataDtos();
		try {

			// test clip time desc order
			LazyLoadResult<FavoriteDataDto> lazyLoadResult = favoriteDataDao.getFavoriteData(userId1, dataType1, null,
					2, false);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(dataId1, lazyLoadResult.getLoadedDtos().get(0).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(dataId2, lazyLoadResult.getLoadedDtos().get(1).getDataId());
			lazyLoadResult = favoriteDataDao.getFavoriteData(userId1, dataType1, lazyLoadResult.getLastLoadPos(), 3,
					false);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(dataId3, lazyLoadResult.getLoadedDtos().get(0).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(dataId4, lazyLoadResult.getLoadedDtos().get(1).getDataId());

			// test clip time asc order
			lazyLoadResult = favoriteDataDao.getFavoriteData(userId1, dataType1, null, 2, true);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(dataId4, lazyLoadResult.getLoadedDtos().get(0).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(dataId3, lazyLoadResult.getLoadedDtos().get(1).getDataId());
			lazyLoadResult = favoriteDataDao.getFavoriteData(userId1, dataType1, lazyLoadResult.getLastLoadPos(), 3,
					true);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(dataId2, lazyLoadResult.getLoadedDtos().get(0).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(dataId1, lazyLoadResult.getLoadedDtos().get(1).getDataId());
		} catch (Exception e) {
			throw e;
		} finally {
			// clean data
			favoriteDataDao.batchDelete(dtos);
		}
	}

	@Test
	public void testGetFavoriteDataByUserIdSortByDataId() {
		// prepare data
		List<FavoriteDataDto> dtos = this.prepareDataDtos();
		try {
			// test dataId desc order
			LazyLoadResult<FavoriteDataDto> lazyLoadResult = favoriteDataDao.getFavoriteDataSortByDataId(userId1, null,
					4, false);
			assertEquals(4, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(dataId6, lazyLoadResult.getLoadedDtos().get(0).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(dataId5, lazyLoadResult.getLoadedDtos().get(1).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(dataId4, lazyLoadResult.getLoadedDtos().get(2).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(3).getUserId());
			assertEquals(dataId3, lazyLoadResult.getLoadedDtos().get(3).getDataId());
			lazyLoadResult = favoriteDataDao.getFavoriteDataSortByDataId(userId1, lazyLoadResult.getLastLoadPos(), 4,
					false);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(dataId2, lazyLoadResult.getLoadedDtos().get(0).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(dataId1, lazyLoadResult.getLoadedDtos().get(1).getDataId());

			// test dataId asc order
			lazyLoadResult = favoriteDataDao.getFavoriteDataSortByDataId(userId1, null, 4, true);
			assertEquals(4, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(dataId1, lazyLoadResult.getLoadedDtos().get(0).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(dataId2, lazyLoadResult.getLoadedDtos().get(1).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(dataId3, lazyLoadResult.getLoadedDtos().get(2).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(3).getUserId());
			assertEquals(dataId4, lazyLoadResult.getLoadedDtos().get(3).getDataId());
			lazyLoadResult = favoriteDataDao.getFavoriteDataSortByDataId(userId1, lazyLoadResult.getLastLoadPos(), 4,
					true);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(dataId5, lazyLoadResult.getLoadedDtos().get(0).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(dataId6, lazyLoadResult.getLoadedDtos().get(1).getDataId());
		} catch (Exception e) {
			throw e;
		} finally {
			// clean data
			favoriteDataDao.batchDelete(dtos);
		}
	}

	@Test
	public void testGetFavoriteDataByUserIdSortByCreateTime() {
		// prepare data
		List<FavoriteDataDto> dtos = this.prepareDataDtos();
		try {
			// test dataId desc order
			LazyLoadResult<FavoriteDataDto> lazyLoadResult = favoriteDataDao.getFavoriteDataSortByCreateTime(userId1,
					null, 4, false);
			assertEquals(4, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(dataId1, lazyLoadResult.getLoadedDtos().get(0).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(dataId2, lazyLoadResult.getLoadedDtos().get(1).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(dataId3, lazyLoadResult.getLoadedDtos().get(2).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(3).getUserId());
			assertEquals(dataId4, lazyLoadResult.getLoadedDtos().get(3).getDataId());
			lazyLoadResult = favoriteDataDao.getFavoriteDataSortByCreateTime(userId1, lazyLoadResult.getLastLoadPos(),
					4, false);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(dataId5, lazyLoadResult.getLoadedDtos().get(0).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(dataId6, lazyLoadResult.getLoadedDtos().get(1).getDataId());
			// test dataId asc order
			lazyLoadResult = favoriteDataDao.getFavoriteDataSortByCreateTime(userId1, null, 4, true);
			assertEquals(4, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(dataId6, lazyLoadResult.getLoadedDtos().get(0).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(dataId5, lazyLoadResult.getLoadedDtos().get(1).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(2).getUserId());
			assertEquals(dataId4, lazyLoadResult.getLoadedDtos().get(2).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(3).getUserId());
			assertEquals(dataId3, lazyLoadResult.getLoadedDtos().get(3).getDataId());
			lazyLoadResult = favoriteDataDao.getFavoriteDataSortByCreateTime(userId1, lazyLoadResult.getLastLoadPos(),
					4, true);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(0).getUserId());
			assertEquals(dataId2, lazyLoadResult.getLoadedDtos().get(0).getDataId());
			assertEquals(userId1, lazyLoadResult.getLoadedDtos().get(1).getUserId());
			assertEquals(dataId1, lazyLoadResult.getLoadedDtos().get(1).getDataId());
		} catch (Exception e) {
			throw e;
		} finally {
			// clean data
			favoriteDataDao.batchDelete(dtos);
		}
	}

	private List<FavoriteDataDto> prepareDataDtos() {
		FavoriteDataDto dataDto1 = FavoriteDataDto.builder().userId(userId1).dataId(dataId1)
				.clipTime(String.valueOf(date.getTime())).dataType(dataType1).build();
		FavoriteDataDto dataDto2 = FavoriteDataDto.builder().userId(userId1).dataId(dataId2)
				.clipTime(String.valueOf(date.getTime() - 2000)).dataType(dataType1).build();
		FavoriteDataDto dataDto3 = FavoriteDataDto.builder().userId(userId1).dataId(dataId3)
				.clipTime(String.valueOf(date.getTime() - 3000)).dataType(dataType1).build();
		FavoriteDataDto dataDto4 = FavoriteDataDto.builder().userId(userId1).dataId(dataId4)
				.clipTime(String.valueOf(date.getTime() - 4000)).dataType(dataType1).build();
		FavoriteDataDto dataDto5 = FavoriteDataDto.builder().userId(userId1).dataId(dataId5)
				.clipTime(String.valueOf(date.getTime() - 5000)).dataType(dataType2).build();
		FavoriteDataDto dataDto6 = FavoriteDataDto.builder().userId(userId1).dataId(dataId6)
				.clipTime(String.valueOf(date.getTime() - 6000)).dataType(dataType2).build();
		FavoriteDataDto dataDto7 = FavoriteDataDto.builder().userId(userId2).dataId(dataId5)
				.clipTime(String.valueOf(date.getTime() - 7000)).dataType(dataType1).build();
		FavoriteDataDto dataDto8 = FavoriteDataDto.builder().userId(userId2).dataId(dataId6)
				.clipTime(String.valueOf(date.getTime() - 8000)).dataType(dataType2).build();
		List<FavoriteDataDto> dtos = Arrays.asList(dataDto1, dataDto2, dataDto3, dataDto4, dataDto5, dataDto6, dataDto7,
				dataDto8);
		favoriteDataDao.batchSave(dtos);
		return dtos;
	}
}

实现FavoriteDataTagDao

根据需求,FavoriteDataTagDto有如下特性:

  • 获取被收藏数据上添加的所有tag, 以userId作为hashKey进行query操作即可,已经在BasicDao中实现
  • 获取所有添加了某个tag的收藏数据,并按收藏时间降序排序,以userId&tagId作为hashKey,对第一个Global Secondary Index进行query操作即可
  • 获取所有添加了某个tag的某种特定类型的收藏数据,并按收藏时间降序排序,以userId&tagId&type作为hashKey,对第二个Global Secondary Index进行query操作即可
package com.jessica.dynamodb.favorite.dao;

import java.util.List;

import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.FavoriteDataTagDto;
import com.jessica.dynamodb.favorite.dto.FavoriteDataType;

public interface FavoriteDataTagDao extends BasicDao<FavoriteDataTagDto> {

	/**
	 * 
	 * get all tag ids for given tagId in tagId order
	 * 
	 * @param userId
	 * @param dataId
	 * @param asc
	 * @return
	 */
	List<String> getTagIdsForData(String userId, String dataId, boolean asc);

	/**
	 * 
	 * get data ids for userId with given tagId
	 * 
	 * @param userId
	 * @param tagId
	 * @param lastLoadSk
	 * @param size
	 * @param asc
	 * @return
	 */
	LazyLoadResult<String> getFavoriteDataIds(String userId, String tagId, String lastLoadSk, Integer size,
			boolean asc);

	/**
	 * get data ids for userId with given tagId and type
	 * 
	 * @param userId
	 * @param tagId
	 * @param dataType
	 * @param lastLoadSk
	 * @param size
	 * @param asc
	 * @return
	 */
	LazyLoadResult<String> getFavoriteDataIds(String userId, String tagId, FavoriteDataType dataType, String lastLoadSk,
			Integer size, boolean asc);
}
package com.jessica.dynamodb.favorite.dao.impl;

import java.util.List;
import java.util.stream.Collectors;

import com.jessica.dynamodb.constant.DynamoDBConstant;
import com.jessica.dynamodb.favorite.dao.FavoriteDataTagDao;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.FavoriteDataTagDto;
import com.jessica.dynamodb.favorite.dto.FavoriteDataType;

public class FavoriteDataTagDaoImpl extends BasicDaoImpl<FavoriteDataTagDto> implements FavoriteDataTagDao {

	@Override
	public List<String> getTagIdsForData(String userId, String dataId, boolean asc) {
		LazyLoadResult<FavoriteDataTagDto> result = this.query(FavoriteDataTagDto.class,
				FavoriteDataTagDto.builder().userId(userId).dataId(dataId).build(), asc, null, null);
		return result.getLoadedDtos().stream().map(FavoriteDataTagDto::getTagId).collect(Collectors.toList());
	}

	@Override
	public LazyLoadResult<String> getFavoriteDataIds(String userId, String tagId, String lastLoadSk, Integer size,
			boolean asc) {
		LazyLoadResult<FavoriteDataTagDto> result = this.queryIndex(FavoriteDataTagDto.class,
				DynamoDBConstant.GSI_ONE_NAME, DynamoDBConstant.GSI_ONE_RANGE_KEY, true,
				FavoriteDataTagDto.builder().userId(userId).tagId(tagId).build(), asc, lastLoadSk, size);
		return convertToStringResult(result);
	}

	@Override
	public LazyLoadResult<String> getFavoriteDataIds(String userId, String tagId, FavoriteDataType dataType,
			String lastLoadSk, Integer size, boolean asc) {
		LazyLoadResult<FavoriteDataTagDto> result = this.queryIndex(FavoriteDataTagDto.class,
				DynamoDBConstant.GSI_TWO_NAME, DynamoDBConstant.GSI_TWO_RANGE_KEY, true,
				FavoriteDataTagDto.builder().userId(userId).tagId(tagId).dataType(dataType).build(), asc, lastLoadSk,
				size);
		return convertToStringResult(result);
	}

	private LazyLoadResult<String> convertToStringResult(LazyLoadResult<FavoriteDataTagDto> dtoLazyLoadResult) {
		return new LazyLoadResult<>(dtoLazyLoadResult.getLoadedDtos().stream().map(FavoriteDataTagDto::getDataId)
				.collect(Collectors.toList()), dtoLazyLoadResult.isHasMore(), dtoLazyLoadResult.getLastLoadPos());
	}
}

测试类

package com.jessica.dynamodb.favorite.dao;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.junit.Test;

import com.jessica.dynamodb.favorite.dao.impl.FavoriteDataTagDaoImpl;
import com.jessica.dynamodb.favorite.data.LazyLoadResult;
import com.jessica.dynamodb.favorite.dto.FavoriteDataTagDto;
import com.jessica.dynamodb.favorite.dto.FavoriteDataType;

public class FavoriteDataTagDaoImplTest {
	FavoriteDataTagDao favoriteDataTagDao = new FavoriteDataTagDaoImpl();
	String userId1 = "userId1";
	String userId2 = "userId2";
	String tagId1 = "tagId1";
	String tagId2 = "tagId2";
	String tagId3 = "tagId3";
	String dataId1 = "dataId1";
	String dataId2 = "dataId2";
	String dataId3 = "dataId3";
	String dataId4 = "dataId4";
	String dataId5 = "dataId5";
	String dataId6 = "dataId6";
	String dataId7 = "dataId7";
	String dataId8 = "dataId8";
	String dataId9 = "dataId9";
	String dataId10 = "dataId10";
	Date nowDate = new Date();
	FavoriteDataType dataType1 = FavoriteDataType.FILE;
	FavoriteDataType dataType2 = FavoriteDataType.IMAGE;

	@Test
	public void getTagIdsForData() {
		// prepare data
		List<FavoriteDataTagDto> dtos = this.prepareDataTagDtos();
		// run test
		try {
			// test clip time desc order
			List<String> tagIds = favoriteDataTagDao.getTagIdsForData(userId1, dataId1, false);
			assertEquals(3, tagIds.size());
			assertEquals(tagId3, tagIds.get(0));
			assertEquals(tagId2, tagIds.get(1));
			assertEquals(tagId1, tagIds.get(2));

			// test clip time asc order
			tagIds = favoriteDataTagDao.getTagIdsForData(userId1, dataId1, true);
			assertEquals(3, tagIds.size());
			assertEquals(tagId1, tagIds.get(0));
			assertEquals(tagId2, tagIds.get(1));
			assertEquals(tagId3, tagIds.get(2));
		} catch (Exception e) {
			throw e;
		} finally {
			// clean data
			favoriteDataTagDao.batchDelete(dtos);
		}
	}

	@Test
	public void testGetFavoriteDataIdsByTagId() {
		// prepare data
		List<FavoriteDataTagDto> dtos = this.prepareDataTagDtos();
		// run test
		try {
			// test clip time desc order
			LazyLoadResult<String> lazyLoadResult = favoriteDataTagDao.getFavoriteDataIds(userId1, tagId1, null, 4,
					false);
			assertEquals(4, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(dataId1, lazyLoadResult.getLoadedDtos().get(0));
			assertEquals(dataId2, lazyLoadResult.getLoadedDtos().get(1));
			assertEquals(dataId3, lazyLoadResult.getLoadedDtos().get(2));
			assertEquals(dataId4, lazyLoadResult.getLoadedDtos().get(3));
			lazyLoadResult = favoriteDataTagDao.getFavoriteDataIds(userId1, tagId1, lazyLoadResult.getLastLoadPos(), 3,
					false);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(dataId5, lazyLoadResult.getLoadedDtos().get(0));
			assertEquals(dataId6, lazyLoadResult.getLoadedDtos().get(1));

			// test clip time asc order
			lazyLoadResult = favoriteDataTagDao.getFavoriteDataIds(userId1, tagId1, null, 4, true);
			assertEquals(4, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(dataId6, lazyLoadResult.getLoadedDtos().get(0));
			assertEquals(dataId5, lazyLoadResult.getLoadedDtos().get(1));
			assertEquals(dataId4, lazyLoadResult.getLoadedDtos().get(2));
			assertEquals(dataId3, lazyLoadResult.getLoadedDtos().get(3));
			lazyLoadResult = favoriteDataTagDao.getFavoriteDataIds(userId1, tagId1, lazyLoadResult.getLastLoadPos(), 3,
					true);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(dataId2, lazyLoadResult.getLoadedDtos().get(0));
			assertEquals(dataId1, lazyLoadResult.getLoadedDtos().get(1));
		} catch (Exception e) {
			throw e;
		} finally {
			// clean data
			favoriteDataTagDao.batchDelete(dtos);
		}
	}

	@Test
	public void testGetFavoriteDataIdsByTagIdAndType() {
		// prepare data
		List<FavoriteDataTagDto> dtos = this.prepareDataTagDtos();
		// run test
		try {
			// test clip time desc order
			LazyLoadResult<String> lazyLoadResult = favoriteDataTagDao.getFavoriteDataIds(userId1, tagId1, dataType1,
					null, 2, false);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(dataId1, lazyLoadResult.getLoadedDtos().get(0));
			assertEquals(dataId2, lazyLoadResult.getLoadedDtos().get(1));
			lazyLoadResult = favoriteDataTagDao.getFavoriteDataIds(userId1, tagId1, dataType1,
					lazyLoadResult.getLastLoadPos(), 3, false);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(dataId3, lazyLoadResult.getLoadedDtos().get(0));
			assertEquals(dataId4, lazyLoadResult.getLoadedDtos().get(1));

			// test clip time asc order
			lazyLoadResult = favoriteDataTagDao.getFavoriteDataIds(userId1, tagId1, dataType1, null, 2, true);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(true, lazyLoadResult.isHasMore());
			assertEquals(dataId4, lazyLoadResult.getLoadedDtos().get(0));
			assertEquals(dataId3, lazyLoadResult.getLoadedDtos().get(1));
			lazyLoadResult = favoriteDataTagDao.getFavoriteDataIds(userId1, tagId1, dataType1,
					lazyLoadResult.getLastLoadPos(), 3, true);
			assertEquals(2, lazyLoadResult.getLoadedDtos().size());
			assertEquals(false, lazyLoadResult.isHasMore());
			assertEquals(dataId2, lazyLoadResult.getLoadedDtos().get(0));
			assertEquals(dataId1, lazyLoadResult.getLoadedDtos().get(1));
		} catch (Exception e) {
			throw e;
		} finally {
			// clean data
			favoriteDataTagDao.batchDelete(dtos);
		}
	}

	private List<FavoriteDataTagDto> prepareDataTagDtos() {
		FavoriteDataTagDto dataTagDto1 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId1).dataId(dataId1)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime())).build();
		FavoriteDataTagDto dataTagDto1_1 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId2).dataId(dataId1)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime() - 1000)).build();
		FavoriteDataTagDto dataTagDto1_2 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId3).dataId(dataId1)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime() - 2000)).build();
		FavoriteDataTagDto dataTagDto2 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId1).dataId(dataId2)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime() - 1000)).build();
		FavoriteDataTagDto dataTagDto3 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId1).dataId(dataId3)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime() - 2000)).build();
		FavoriteDataTagDto dataTagDto4 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId1).dataId(dataId4)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime() - 3000)).build();
		FavoriteDataTagDto dataTagDto5 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId1).dataId(dataId5)
				.dataType(dataType2).clipTime(String.valueOf(nowDate.getTime() - 4000)).build();
		FavoriteDataTagDto dataTagDto6 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId1).dataId(dataId6)
				.dataType(dataType2).clipTime(String.valueOf(nowDate.getTime() - 5000)).build();
		FavoriteDataTagDto dataTagDto7 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId2).dataId(dataId7)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime() - 6000)).build();
		FavoriteDataTagDto dataTagDto8 = FavoriteDataTagDto.builder().userId(userId1).tagId(tagId2).dataId(dataId8)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime() - 7000)).build();
		FavoriteDataTagDto dataTagDto9 = FavoriteDataTagDto.builder().userId(userId2).tagId(tagId1).dataId(dataId9)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime() - 8000)).build();
		FavoriteDataTagDto dataTagDto10 = FavoriteDataTagDto.builder().userId(userId2).tagId(tagId1).dataId(dataId10)
				.dataType(dataType1).clipTime(String.valueOf(nowDate.getTime() - 9000)).build();
		List<FavoriteDataTagDto> dtos = Arrays.asList(dataTagDto1, dataTagDto1_1, dataTagDto1_2, dataTagDto2,
				dataTagDto3, dataTagDto4, dataTagDto5, dataTagDto6, dataTagDto7, dataTagDto8, dataTagDto9,
				dataTagDto10);
		favoriteDataTagDao.batchSave(dtos);
		return dtos;
	}
}

完整代码

GitHub - JessicaWin/dynamodb-in-action at dao-impl

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值