(2023打卡)每日两道面试题|一道算法题|7月4日
1.面试题
1.1.缓存穿透
缓存穿透:查询一个不存在的数据,Mysql查询不到数据也不会直接写入缓存,就会导致每次请求都查数据库,导致宕机
**解决方案一:**缓存空数据,查询返回的数据为空,仍把这个空结果进行缓存
缺点实例:比如id为1的数据本来为null,但是后来添加了一条数据到Mysql,但是缓存中还是null,导致缓存和数据库中的数据不一致
**解决方案二:**布隆过滤器
bitmap(位图):相当于是一个以(bit)位为单位的数据,数组中每个单元只能存储二进制数0或1
**布隆过滤器作用:**布隆过滤器可以用于检索一个元素是否在一个集合中。
误判率:数组越小误判率就越大,数据越大误判率就越小,但是同时带来了更多的内存消耗。
优点:内存占用较少、没有多余key
缺点:实现复杂、存在误判
总结(缓存穿透):
- 什么是缓存穿透、怎么解决
- 缓存穿透:查询一个不存在的数据,mysql查询不到数据也不会直接写入缓存,就会导致每次请求都查数据库
- 解决方案一:缓存空数据
- 解决方案二:布隆过滤器
面试官:什么是缓存穿透?怎么解决?
什么是缓存穿透
查询一个一定不存在的数据,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到DB去查询,可能导致DB挂掉,这种情况大概率是遭到了攻击
解决方案
缓存空数据:给不存在的id赋值一个空数据,仍然把这个空数据进行缓存。
布隆过滤器:布隆过滤器主要是用于检索一个元素是否在一个集合中,我们当时使用的是redisson实现的布隆过滤器,
它的底层主要是先去初始化一个比较大的数组,里面存放的二级制0或1,在一开始都是0,当一个key来了之后经过3次hash计算。模于数组长度找到数据的下标然后把数组中原来的0改为1,这样的话,三个数组的位置就能标明一个key的存在,查找的过程也是一样的
1.2.缓存击穿
缓存击穿:给某一个key设置了过期时间,当key过期的时候,恰好这时间点对这个key有大量的并发请求过来,这些并发的请求可能会瞬间把DB压垮
解决方案一:互斥锁
解决方案二:逻辑过期(不设置过期时间)
设置一个expire过期时间字段,使用它用于描述
总结(缓存击穿):
- 缓存击穿:给某个key设置了过期时间,当key过期的时候,恰好这时间点对这个key有大量的并发请求过来,这些并发的请求可能会瞬间把DB压垮
- 解决方案一:互斥锁,强一致,性能差
- 解决方案二:逻辑过期,高可用,性能优,不能保证数据绝对一致
面试官:什么是缓存击穿?怎么解决
缓存击穿是一个key设置了过期时间,在key的时间过期的同时,有大量并发的请求,请求这个key这个时候就会导致DB不堪重负,结果可能会宕机
有两种解决方案:
一互斥锁:当缓存失效时,不立即去load db,先使用redis的setnx去设置一个互斥锁,当操作成功返回时再进行load db的操作并回设缓存,否则重试get缓存的方法
二逻辑过期
1.不给指定key设置过期时间,取而代之的是给这个key新增一个expire(过期时间)字段
2.当查询时先从redis中取出数据,判断当前数据是否过期
3.如果过期则开通另外一个线程做数据同步,当前线程正常返回数据,这个数据不是最新数据
2.算法题
提示:
1 <= nums.length <= 300
1 <= nums[i].length <= 500
0 <= nums[i][j] <= 103
2.1.分析:
先将二维数组排序,得到从小到大的顺序,然后通过比对每列的大小确定最大值,最后加到一个结果变量中
class Solution {
public int matrixSum(int[][] nums) {
//最后结果
int res=0;
//获取列数
int m=nums.length;
//获取行数
int n=nums[0].length;
for(int i=0;i<m;i++){
//将每列中的的数组进行从小到大排序
Arrays.sort(nums[i]);
}
for(int j=0;j<n;j++){
//每遍历完一列归零
int maxVal=0;
for(int i=0;i<m;i++){
//比较出一行中的最大值
maxVal=Math.max(maxVal,nums[i][j]);
//源码分析
//public static int max(int a, int b) {
//return (a >= b) ? a : b;
//}
}
//最后加到返回的结果内
res+=maxVal;
}
//返回结果
return res;
}
}
以上图为例,当排序完成之后nums二维数组则会是{{1,2,7},{2,4,6},{3,5,6},{1,2,3}},以上两个For循环,加上Math中的取最大值方法
对应的值会是
第一次遍历,需要注意的是这取的是每一列的值,仔细查看以下代码是先遍历j再遍历i
nums[0][0]=1
nums[1][0]=2
nums[2][0]=3
nums[3][0]=1
后面根据以上图片以此类推
for(int j=0;j<n;j++){
for(int i=0;i<m;i++){
maxVal=Math.max(maxVal,nums[i][j]);
2.2.使用技术重点:
Arrays中的sort方法用于排序,Math中max用于找最大值,通过两个For嵌套得到以每列作为对比的,目的得出每次循环的结果