前言:关于集成Ehcache3的集成,需要了解的可以出门左转:
https://blog.csdn.net/qq_42755868/article/details/143870473 这里
本文也是基于这个前置条件写的。大佬可以忽略哈。
基于上文:我们在做分页查询的时候,可以将分页数据进行缓存。比如以下low方案:
该方案:诸如此类比较简单易上手,但是对于缓存数据的维护来说,有点小麻烦,另外过大的key也可能会一定程度的影响缓存性能。
所以:看方案二,我这里制作到了方案二,还有更好的(恕鄙人无能)。
@Service
@Transactional
public class UsersServiceImple implements IUsersService {//JPA 简化sql,用于替换usermapper@Autowiredprivate UsersRepository usersRepository;@Cacheable(value="tests2"/*注意这个cache需要在ehcache里配一下*/,key="getMethodName().concat('_').concat(T(String)."+"valueOf(#pageable.pageNumber)"+".concat('::').concat(#pageable.pageSize))")@Overridepublic Page<Users> findUserByPage(Pageable pageable) {return this.usersRepository.findAll(pageable);}
}
方案二:在数据库IO层面,可能会碰到大表数据查询较慢,这里如果只分页查询id,发挥主键索引的效果,性能应该可以得到提升。
基于这一点我想到的是:还有优化思考空间~(比如:事务相关)
1. 分页查询数据库的ID列表2. 根据ID列表去获取缓存中通过(ID,Bean)形式存储的bean实例,2.1 (注意这个bean实例的维护需要做的全面一点,比如CRUD相关操作,我这里只演示分页查询的啦)3. 如果全命中缓存中的记录,则封装返回查询的结果,这里如果使用的缓存支持批量操作,会更好,如redis的mget之类,结合Pipleline会更好的发挥缓存的性能。4. 如果部分命中,或者0命中。暂存命中部分的记录,然后整理出未命中的id,批量查询出数据库的记录。将该记录一并合入到暂存的记录中。同时,将未命中的结果更新到缓存中。5. 返回结果。搞掂!!!
@Repository
public interface UsersRepository extends JpaRepository<Users,Integer> {@Query(nativeQuery = true, value = "select id from users")Page<Integer> findAllIds( Pageable pageable);List<Users> findByIdIn(List<Integer> ids);
}
@Service
@Transactional
public class UsersServiceImple implements IUsersService {@AutowiredCacheManager cacheManager;//JPA 简化sql,用于替换usermapper@Autowiredprivate UsersRepository usersRepository;//采用,分页查询id,然后通过id批量获取存入到缓存的实例@Overridepublic Page<Users> findUserByPage2(Pageable pageable) {//return this.usersRepository.findAll(pageable);//原始数据库策略//做缓存分页查询策略Cache cache = cacheManager.getCache("users");Page<Users> usersPage = null;if(cache==null){//0、缓存死亡(无缓存),从数据库中去获取,后续查询数据由其他接口更新进缓存usersPage = this.usersRepository.findAll(pageable);}else{//1、获取分页查询的id虚拟集,充分发挥库的主键索引优势Page<Integer> idListPageDB = this.usersRepository.findAllIds(pageable);List<Users> usersCache = getPageEleFromCache(idListPageDB, cache);//2、剥离缓存中没有命中的id列表List<Integer> idListDB = idListPageDB.getContent().stream().collect(Collectors.toList());usersCache.forEach(users -> idListDB.removeIf(ele->ele.compareTo(users.getId())==0));//3、当存在缓存中没有命中的id列表,则从数据库中去获取数据记录if(!CollectionUtils.isEmpty(idListDB)){//3.1 获取数据库中的未命中记录System.out.println("缓存中存在没有数据情况,需要到数据空去获取!!!!!");List<Users> usersDB = this.usersRepository.findByIdIn(idListDB);usersCache.addAll(usersDB);//3.2 尝试将未在缓存中查到的数据重新放回缓存中usersDB.forEach(users -> cache.put(users.getId(),users));}else{System.out.println("从缓存中获取到内容");}//4、将最终的记录封装到分页类中usersPage = new PageImpl<>(usersCache,pageable,idListPageDB.getTotalElements());}return usersPage;}/*** 根据Id列表,获取缓存中的存放的目标元素* @param idListPageDB* @param cache* @return*/private static List<Users> getPageEleFromCache(Page<Integer> idListPageDB, Cache cache) {List<Users> usersListCache = idListPageDB.stream().map(id -> cache.get(id)!=null?(Users)(cache.get(id).get()):null).filter(ele->ele!=null).collect(Collectors.toList());return usersListCache;}
}
附:部分代码的说明
在这里插入图片描述
测试: