网站建设分金手指专业十三/建设一个网站的具体步骤
此方法主要理解 分布式锁工作原理:推荐使用
学习redisson 了解工作原理: 特殊缓存数据 写多 及时性高,推荐Redisson
https://blog.csdn.net/qq_17040587/article/details/121516553
常规数据(都多写少,及时性一致性要求不高的数据)推荐用springCache的例子
https://blog.csdn.net/qq_17040587/article/details/121522421
为了防止热数据的缓存过期,造成高并发进来同时出发数据库操作,造成数据库压力过大崩溃。采用加锁操作。只允许一个请求进来 去执行查看,其他的同时进来的请求,等待。。进来后再次检查缓存,如果有数据就命中缓存。
// 同步代码块
// synchronized(this) SpringBoot的所有组件 在容器中都是单例的。
synchronized (this){}
例:处理redis缓存的模式
- 判断redis
请求进来,先查询redis是否有有效数据,有则读取返回
redis没有,操作数据库处理- 数据库处理
为了防止缓存击穿, 采纳本地所synchronized 仅让一个请求A进来操作数据库
同时也让其他其他请求拿到数据不再操作库 A释放synchronized 前,把缓存数据写好。数据库处理最前端加入先判断缓存逻辑。
@Autowiredprivate StringRedisTemplate stringRedisTemplate;...//调取数据逻辑 先考虑redis 无数据再考虑数据库操作public Map<String, List<T>> getData() {//给缓存存放json 拿出的json字符串需要逆转为对象类型【序列化与反序列化】//1.从缓存取出的jsonString redisString = stringRedisTemplate.opsForValue().get(INDEX);if(StringUtils.isEmpty(redisString)){System.out.println("缓存不命中 查数据库...");//2.缓存中没有 查询数据库Map<String, List<T>> dataFromDb= getDataFromDb();return dataFromDb;}System.out.println("缓存命中 直接返回...");//2. - 直接把缓存取出结果 逆转指定类型Map<String, List<T>> result = JSON.parseObject(redisString, new TypeReference< Map<String, List<T>>>(){});return result;}public Map<String, List<T>> getDataFromDb() {/*同步代码块只要是同一把锁 就能锁住需要这个锁定的所有线程synchronized(this) SpringBoot的所有组件 在容器中都是单例的。TODO 本地锁 synchronized JUC(lock) 在分布式情况下 想要锁住所有 必须用分布式锁*/synchronized (this){//得到锁后 我们再去缓存在确认一次 如果没有再去查询 这个操作是为了并发进来操作数据库的非第一次请求,让他们从缓存中在此查一下 就拿到了第一次请求放置的数据内容String s= stringRedisTemplate.opsForValue().get(INDEX);if(!StringUtils.isEmpty(s)){Map<String, List<T>> result = JSON.parseObject(s,new TypeReference<Map<String, List<T>>>(){});return result;}System.out.println("进入了查数据库逻辑");List<T> selectList = baseMapper.selectList(null); return selectList;}}
在读取到数据后,需要把写入缓存的操作,也在线程锁内完成。写缓存(如:redis 网络操作,有间隙时间损耗),这个间隙会有请求进来再次唤起操作数据库。
springBoot的容器为单例模式存在,才保证了本地锁的有效性。但是在分布式中,本地锁,也只能有效的锁住本地线程,对于其他服务单例,也是没法有效锁定。