-
表结构
由于查询标签信息和教师信息需要反复多次对数据库进行查询,每次查询几十毫秒,加起来可能要好几秒,严重影响性能。我们可以增加缓存,这样软件的效率可以提升好多倍。教师的数据可能会有经常变化,我们可以设置一个过期策略,比如一个小时就清空教师散列表,重新加载。
-
代码
IUserService创建抽象方法/** * 返回缓存的全部老师昵称和老师信息的Map * 用于快速的根据老师名称找到老师信息 * @return */ Map<String,User> getMasterMap();
实现抽象方法
新建集合和定时器
private final List<User> masters = new CopyOnWriteArrayList<>();
private final Map<String, User> mastersMap = new ConcurrentHashMap<>();
private final Timer timer = new Timer();
//代码块在创建对象的时候执行
{
//每个小时执行一次,清楚缓存,实现缓存过期功能
timer.schedule(new TimerTask() {
@Override
public void run() {
synchronized (masters){
masters.clear();
mastersMap.clear();
}
}
},1000*60*60,1000*60*60);
}
- List和Map的区别
List:是存储单列数据的集合,存储的数据是有序并且是可以重复的
Map:存储双列数据的集合,通过键值对存储数据,存储 的数据是无序的,Key值不能重复,value值可以重复 - CopyOnWriteArrayList可以实现读无锁,写加锁,是一种读写分离的并发策略。适用于绝大部分都是读,偶尔写的场景。
- ConcurrentHashMap<>()可以解决并发问题,具体后面详细笔记。
- 代码块创建计时器,没一个小时同步清除缓存。
重写方法
/*
User表中,所有type为1的是解答问题老师
*/
@Override
public List<User> getMaster() {
if (masters.isEmpty()){
synchronized (masters) {
/*
user表中type属性都是回答问题的老师
*/
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("type", 1);
List<User> list = userMapper.selectList(queryWrapper);
//初始化masterMap缓存
masters.addAll(list);
masters.forEach(master -> mastersMap.put(master.getNickname(),master));
//将查询的结果集中的密码设为空. 密码传入前端不符合规范.
masters.forEach(mastersP -> mastersP.setPassword(""));
}
}
return masters;
}
@Override
public Map<String, User> getMasterMap() {
if (mastersMap.isEmpty()){
getMaster();
}
return mastersMap;
}
测试方法
@Test
public void getMasterMap(){
Map<String,User> map = userService.getMasterMap();
map.forEach((nickname,master)-> System.out.println(nickname+":"+master));
}