考虑到一个问题相关到标签一旦选定就很少更改,所以在Question设计一个冗余类tag_names,储存当前问题相关名称,这样查询标签的时候就不用进行复杂关联查询了。
- 但是客服端如何做到完整的Tag信息呢,可以在服务器端利用缓存的tag信息组装一个信息。
首先为Question类型添加tags属性,表示当前Question完整Tag信息利用注解@TableField(exist = false)通知MyBatisPlus,这个属性不来自数据库。避免发生映射故障。
为了提高查询性能,在TagServiceImpl中添加一个散列表,缓存全部Tag信息。这里为了解决散列表被并发访问的问题,采用ConcurrentHashMap类型散列表,这个类来自Java并发包,相对于HashMap提供了并发安全功能。并且其内部分段式加锁机制,可以保证并且安全情况下具有更好的访问性能。这个散列表在加载Tag数据时候一同被初始化。
接口
Map<String, Tag> getName2TagMap();
实现
//注入map,key是String类型,value是tag类型
private final Map<String,Tag> name2TagMap = new ConcurrentHashMap<>();
@Override
public List<Tag> getTags() {
if(tags.isEmpty()){
//进行同步
synchronized (tags){
//再次检查
if (tags.isEmpty()){
//list() 是Mybatis plus提供的方法,在ServiceImpl中定义
//继承与ServiceImpl的方法,方法的作用就是返回数据库中Tag对象
tags.addAll(list());
//tag的name作为key,把tag放进去
tags.forEach(tag -> name2TagMap.put(tag.getName(),tag));
log.debug("加载tag列表{}",tags);
log.debug("加载了Map{}",name2TagMap);
}
}
}
return tags;
}
@Override
public Map<String, Tag> getName2TagMap() {
if (tags.isEmpty()){
getTags();
}
return name2TagMap;
}
测试方法
@Test
public void getName2TagMap(){
Map<String,Tag > tagMap = tagService.getName2TagMap();
tagMap.forEach((name,tag) -> System.out.println(name + ":" + tag));
}