1.无限极数据获取
1.递归
详细见上一篇总结
2.循环
循环-一次性把所以的节点都查询出来,再来组织他们关系
①查询所有节点
②如果是第一级放入返回的list
③如果是非第一级,建立父子关系
1 获取服务 map(id-node)
2 把自己作为父亲一个儿子放进去就ok children=new Array<>();
具体代码如下
@Service
public class CourseTypeServiceImpl extends ServiceImpl<CourseTypeMapper, CourseType> implements ICourseTypeService {
@Autowired
private CourseTypeMapper courseTypeMapper;
//和mapper差不多,mapper操作的是数据库的数据,而换成操作的是redis数据
@Autowired
private ICourseTypeCache courseTypeCache;
@Override
public List<CourseType> treeData(long pid) {
System.out.println("bd....");
//否则先查询数据库,放入换成后再返回
//递归
// return treeDataRecursion(pid);
//循环
return treeDataLoop(pid);
}
//循环方案 一条sql自己组织关系
private List<CourseType> treeDataLoop(Long pid){
//1.查询所有节点
List<CourseType> courseTypes = courseTypeMapper.selectList(null);
//为了查询父亲方便,我建立所有节点的一个key(Id)-vue(Node)集合 n
HashMap<Long, CourseType> allNodeDto = new HashMap<>();
for (CourseType courseType : courseTypes) {
allNodeDto.put(courseType.getId(),courseType);
}
//2.组织关系
List<CourseType> result=new ArrayList<>();
for (CourseType courseType : courseTypes) {
//如果是一级节点就放入result
if (courseType.getPid().intValue()==0){
result.add(courseType);
}else {
//2.2 不是一级节点要建立父子关系-把自己作为父亲一个儿子添加进去
//2.2.1 获取父亲
Long pidTmp = courseType.getPid();
//提前建立id和Node直接关系,直接获取
CourseType parent = allNodeDto.get(pidTmp);
//给父亲添加儿子
parent.getChildren().add(courseType);
}
}
return result;
}
2.缓存优化
1.对访问量多但是修改次数少的数据可以使用redis缓存来减少对数据库的压力,从而达到优化
2.使用集群的时候就使用redis缓存,而jpa这些的缓存是在单项目架构的时候使用
3.使用缓存的好处:
减轻数据库压力
提高访问速度,增强用户体验
4.我们缓存数据很多?-redis集群
主从复制-单主故障
哨兵模式-每个节点数据都是一样
redis-cluster: 单点故障,高并发,大量数据
redis的使用步骤
1.设置redis的密码
在此文件中进行修改
然年在文件中搜索requirepass
2…导入redis
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
3…配置redis的配置文件
redis.properties
redis.host=127.0.0.1 #ip地址
redis.port=6379 #用哪个端口
redis.password=redis的密码
redis.timeout=1000
4.在工具类中设置连接池的方法
/**
* 获取连接对象
*/
public enum RedisUtils {
INSTANCE;
static JedisPool jedisPool=null;
static {
//1 创建连接池配置对象
JedisPoolConfig config = new JedisPoolConfig();
//2 进行配置-四个配置
config.setMaxIdle(1);//最小连接数
config.setMaxTotal(11);//最大连接数
config.setMaxWaitMillis(10 * 1000L);//最长等待时间
config.setTestOnBorrow(true);//测试连接时是否畅通
//3 通过配置对象创建连接池对象
Properties properties = null;
try {
properties = new Properties();
properties.load(RedisUtils.class.getClassLoader().getResourceAsStream("redis.properties"));
} catch (IOException e) {
e.printStackTrace();
}
String host = properties.getProperty("redis.host");
String port = properties.getProperty("redis.port");
String password = properties.getProperty("redis.password");
String timeout = properties.getProperty("redis.timeout");
System.out.println(host);
System.out.println(port);
System.out.println(password);
System.out.println(timeout);
jedisPool = new JedisPool(config, host, Integer.valueOf(port),Integer.valueOf(timeout), password);
}
//获取连接
public Jedis getSource() {
return jedisPool.getResource();
}
//关闭资源
public void closeSource(Jedis jedis) {
if (jedis != null) {
jedis.close();
}
}
/**
* 设置字符值
*
* @param key
* @param
*/
public void del(String key) {
Jedis jedis = getSource();
jedis.del(key);
closeSource(jedis);
}
/**
* 设置字符值
*
* @param key
* @param value
*/
public void set(String key, String value) {
Jedis jedis = getSource();
jedis.set(key, value);
closeSource(jedis);
}
/**
* 设置
* @param key
* @param value
*/
public void set(byte[] key, byte[] value) {
Jedis jedis = getSource();
jedis.set(key, value);
closeSource(jedis);
}
/**
*
* @param key
* @return
*/
public byte[] get(byte[] key) {
Jedis jedis = getSource();
try {
return jedis.get(key);
} catch (Exception e) {
e.printStackTrace();
} finally {
closeSource(jedis);
}
return null;
}
/**
* 设置字符值
*
* @param key
*/
public String get(String key) {
Jedis jedis = getSource();
try {
return jedis.get(key);
} catch (Exception e) {
e.printStackTrace();
} finally {
closeSource(jedis);
}
return null;
}
}
5.写crud的方法
@RestController
/**
* 增/修改 set
* 删除 del
* 查询 get
*/
@RequestMapping("/redis")
public class RedisController {
@PostMapping
public AjaxResult add(
@RequestParam(value = "key",required = true) String key,
@RequestParam(value = "value",required = true) String value)
{
try
{
RedisUtils.INSTANCE.set(key,value);
return AjaxResult.me();
}catch (Exception e){
e.printStackTrace();
return AjaxResult.me().setSuccess(false).setMessage("添加失败");
}
}
@DeleteMapping
public AjaxResult del(@RequestParam(value = "key",required = true) String key)
{
try
{
RedisUtils.INSTANCE.del(key);
return AjaxResult.me();
}catch (Exception e){
e.printStackTrace();
return AjaxResult.me().setSuccess(false).setMessage("删除失败");
}
}
@GetMapping
public String get(@RequestParam(value = "key",required = true) String key)
{
try
{
return RedisUtils.INSTANCE.get(key);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
缓存问题以及一些面试题
缓存穿透,缓存击穿,缓存雪崩-面试必备技能
https://blog.csdn.net/kongtiao5/article/details/82771694
缓存穿透:高并发访问数据库中不存在数据,放入缓存的数据也没有,击穿缓存每次都要查询数据库.
1)有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层数据库的查询压力。
2)另外也有一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。
缓存击穿:一个key过期,又来高并发访问. 直接高并发访问数据库.
1)让热点数据永远不过期.
2)加互斥锁,互斥锁参考代码如下 我在访问数据库是你就不要访问
缓存雪崩:一堆key同时过期
设置过期时间不一致就ok. 热点数据永远不过期
if (courseTypesOfDb == null || courseTypesOfDb.size()<1){
//缓存穿透
redisClient.add(COURSETYPE_KEY_IN_CACHE,"[]");
}else{
//转换为json字符串
String jsonArrStr = JSONArray.toJSONString(courseTypesOfDb);
//设置获取
//缓存数据永远不过期 缓存击穿 缓存雪崩
redisClient.add(COURSETYPE_KEY_IN_CACHE,jsonArrStr);
}
三 服务调用
服务间调用–feign-ribbon,hystrix(负载均衡,服务高可用(熔断))
外部调用服务-都是通过zuul-ribbon,hystrix(负载均衡,服务高可用(熔断))
无论是服务间调用或者是外部调用都是进行负载均衡和熔断+降级。
commonService
redis服务是给服务间调用,前端不能直接操作redis
fastdfs直接给前端调用,前端可以直接删除图片和删除图片
微服务架构(springcloud)中是怎么做负载均衡?
feign
微服务架构(springcloud)中是怎么做熔断和降级?
hystrix