redis
redis缓存
缓存穿透
布隆过滤器主要是用于检索一个元素是否在一个集合中。我们当时使用的是 redisson实现的布隆过滤器。 它的底层主要是先去初始化一个比较大数组,里面存放的二进制0或1。在一 开始都是0,当一个key来了之后经过3次hash计算,模于数组长度找到数据 的下标然后把数组中原来的0改为1,这样的话,三个数组的位置就能标明一 个key的存在。查找的过程也是一样的。
当然是有缺点的,布隆过滤器有可能会产生一定的误判,我们一般可以设置 这个误判率,大概不会超过5%,其实这个误判是必然存在的,要不就得增 加数组的长度,其实已经算是很划分了,5%以内的误判率一般的项目也能 接受,不至于高并发下压倒数据库。
缓存雪崩![](https://i-blog.csdnimg.cn/blog_migrate/157628651470b7bf6dc8ad7b11a4c4e0.png)
双写一致
强一致性:读写锁
异步通知:
数据持久化
数据过期策略
redis的过期策略是惰性删除和定期删除配合使用
数据淘汰策略![](https://i-blog.csdnimg.cn/blog_migrate/78b1d1f2a2af225d8c16873c1c6ed183.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2e3162914fba15d55d5dda3b1b5769f2.png)
分布式锁
主从复制![](https://i-blog.csdnimg.cn/blog_migrate/f793f2a89481c950360dbb5a1394baae.png)
主从复制原理
哨兵模式
redis是单线程快的原因
redis业务场景自我整理
spring
考察范围
spring框架中的单列bean是线程安全的码
spring AOP详解
结果输出:
spring事务失效的原因
只有代理的类才会被切入,我们在controller层调用service的方法的时候,是可以被切入的,但是如果我们在service层 A方法中,调用B方法,切点切的是B方法,那么这时候是不会切入的,解决办法就是如上所示,在A方法中使用((Service)AopContext.currentProxy()).B() 来调用B方法,这样一来,就能切入了!
描述时可以加上应用场景,什么时候出现过事务失效
package com.hmdp.service.impl;
import com.hmdp.dto.Result;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisIdWorker;
import com.hmdp.utils.UserHolder;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.Collections;
/**
* <p>
* 服务实现类
* </p>
*
* @author 虎哥
* @since 2021-12-22
*/
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {
@Autowired
private ISeckillVoucherService seckillVoucherService;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
RedissonClient redissonClient;
private static final DefaultRedisScript<Long> SECKILL_SCRIPT;
static {
SECKILL_SCRIPT = new DefaultRedisScript<>();
SECKILL_SCRIPT.setLocation(new ClassPathResource("seckill.lua"));
SECKILL_SCRIPT.setResultType(Long.class);
}
@Override
public Result seckillVoucher(Long voucherId) {
// //查询秒杀时间
// SeckillVoucher seckillVoucher = seckillVoucherService.getById(voucherId);
// if (seckillVoucher==null){
// return Result.fail("秒杀商品不存在");
// }
// if (seckillVoucher.getBeginTime().isAfter(LocalDateTime.now())){
// return Result.fail("秒杀未开始");
// }
// if (seckillVoucher.getEndTime().isBefore(LocalDateTime.now())){
// return Result.fail("秒杀已结束");
// }
// if (seckillVoucher.getStock()<1){
// return Result.fail("库存不足");
// }
// Long userId = UserHolder.getUser().getId();
// //加锁:单机下使用synchronized
synchronized (userId.toString().intern()) {
RedisLock redisLock=new RedisLock("order:"+userId,stringRedisTemplate);
redisClient.getL
// RLock lock = redissonClient.getLock("order:" + userId);
// boolean b = lock.tryLock();
// if (!b){
// return Result.fail("每个用户只能购买一次");
// }
// //交给spring后实现事务
// try {
// IVoucherOrderService proxy = (IVoucherOrderService)AopContext.currentProxy();
// return proxy.createOrder(voucherId);
// } finally {
// lock.unlock();
// }
Long userId = UserHolder.getUser().getId();
Long redult = stringRedisTemplate.execute(SECKILL_SCRIPT,
Collections.emptyList(),
voucherId.toString(), userId.toString());
int r = redult.intValue();
if (r != 0) {
return Result.fail(r == 1 ? "库存不足" : "不能重复下单");
}
RedisIdWorker redisIdWorker = new RedisIdWorker(stringRedisTemplate);
long orderId = redisIdWorker.nextId("order");
return Result.ok(0);
}
@Transactional
public Result createOrder(Long voucherId) {
RedisIdWorker redisIdWorker = new RedisIdWorker(stringRedisTemplate);
long orderId = redisIdWorker.nextId("order");
Long userId = UserHolder.getUser().getId();
//实现一人一单
Integer count = query().eq("user_id", userId)
.eq("voucher_id", voucherId).select().count();
if (count > 0) {
return Result.fail("用户已经购买过一次了");
}
//扣减库存
boolean b = seckillVoucherService.update()
.setSql("stock=stock-1")
.eq("voucher_id", voucherId)
.gt("stock", 0)
.update();
if (!b) {
return Result.fail("秒杀失败");
}
//添加订单信息
VoucherOrder voucherOrder = new VoucherOrder();
voucherOrder.setUserId(userId);
voucherOrder.setVoucherId(voucherId);
voucherOrder.setId(orderId);
save(voucherOrder);
return Result.ok(orderId);
}
}
spring中Bean的生命周期![](https://i-blog.csdnimg.cn/blog_migrate/2726fddc64fd1f0a0ff4e0f75a4309d4.png)
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class User implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean {
public User() {
System.out.println("User的构造方法执行了.........");
}
private String name ;
@Value("张三")
public void setName(String name) {
System.out.println("setName方法执行了.........");
}
@Override
public void setBeanName(String name) {
System.out.println("setBeanName方法执行了.........");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("setBeanFactory方法执行了.........");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("setApplicationContext方法执行了........");
}
@PostConstruct
public void init() {
System.out.println("init方法执行了.................");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet方法执行了........");
}
@PreDestroy
public void destory() {
System.out.println("destory方法执行了...............");
}
}
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("user")) {
System.out.println("postProcessBeforeInitialization方法执行了->user对象初始化方法前开始增强....");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("user")) {
System.out.println("postProcessAfterInitialization->user对象初始化方法后开始增强....");
//cglib代理对象
Enhancer enhancer = new Enhancer();
//设置需要增强的类
enhancer.setSuperclass(bean.getClass());
//执行回调方法,增强方法
enhancer.setCallback(new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
//执行目标方法
return method.invoke(method,objects);
}
});
//创建代理对象
return enhancer.create();
}
return bean;
}
}
输出结果:
User的构造方法执行了.........
setName方法执行了.........
setBeanName方法执行了.........
setBeanFactory方法执行了.........
setApplicationContext方法执行了........
postProcessBeforeInitialization方法执行了->user对象初始化方法前开始增强....
init方法执行了.................
afterPropertiesSet方法执行了........
postProcessAfterInitialization->user对象初始化方法后开始增强....
User的构造方法执行了.........
public java.lang.String java.lang.Object.toString()
spring循环依赖![](https://i-blog.csdnimg.cn/blog_migrate/706d706cfa6f4ad9140a8dffdd60ac81.png)
spring MVC请求
springboot自动配置
spring常见的注解
线程池
如何确定核心线程数
线程池的种类
为什么不建议使用Executors创建线程
RabbitMQ
RabbitMQ如何保证消息不丢失
RabbitMQ消息的重复消费问题如何解决![](https://i-blog.csdnimg.cn/blog_migrate/4b502ae704e6e9bc349f8a114cd208d7.png)
死信交换机
100万的数据堆积在MQ中如何解决
RabbitMQ高可用机制了解过嘛
集合
数组
ArrayList底层实现原理
数组转List和List转数组![](https://i-blog.csdnimg.cn/blog_migrate/3deacc967d91f8192914935077077c88.png)
ArrayList和LinkedList的区别
二叉树
红黑树
散列冲突
HashMap实现原理
HashMap中Put方法执行流程
Hashmap扩容机制
Hashmap寻址算法和数组长度为2的n次幂![](https://i-blog.csdnimg.cn/blog_migrate/cc270b9927835c0a581240ba6d3328a1.png)
JVM
程序计数器
堆
堆和栈的区别
方法区
什么是类加载器
双亲委派
类装载的过程
什么是可以判定为垃圾
JVM中的回收算法
JVM中分代回收
垃圾回收器
强软弱虚引用的区别
JVM调优的参数可以在哪里设置 ![](https://i-blog.csdnimg.cn/blog_migrate/1da2ccb31a98f34f8d3ee41bd7fb2d3d.png)
JVM的调优参数
JVM调优工具 ![](https://i-blog.csdnimg.cn/blog_migrate/cbbb045cdd3fe6a28903e508d28d5479.png)
JVM内存泄漏排查思路
JVM查看CPU飙高
微服务
spring Cloud常用组件有哪些
注册中心和服务中心
Ribbon的负载均衡策略有哪些?如何自定义负载均衡策略
服务雪崩是什么,怎末解决
微服务是如何让监控的
限流算法和如何实现限流
CAP和BASE
分布式事务Seata
接口幂等性的实现方式
分布式任务调度
设计模式
工厂模式
创建对象和对象调用者解耦
策略模式![](https://i-blog.csdnimg.cn/blog_migrate/4a6625b530d9e4c631d3dc5931eb9f5d.png)
责任链模式
spring中的设计模式
Spring 中经典的 9 种设计模式,打死也要记住啊! - 知乎 (zhihu.com)
mysql
如何定位慢查询日志
SQL执行很慢,如何分析
索引
Mysql超大分页处理
索引创建的原则有哪些?
什么时候会索引失效
SQL优化经验
Mysql事务解决方案
redo log和undo log的区别
事务中的隔离性是如何保证的?
主从复制同步原理
Mybatis
Myabtis执行流程
mybatis是否支持延迟加载
mybatis缓存
线程
创建线程的方式
runnable和callable的区别
run()和start()方法的区别
线程包括那些状态
新建3个线程如何保证他们顺序执行
notify和notifyAll的区别
wait()和sleep方法的不同
正在执行的线程如何打断
使用推出标记代码![](https://i-blog.csdnimg.cn/blog_migrate/64ae14a3ec6aa85295d5b02d91b225ad.png)
打断线程代码
synchronizatied锁升级
JMM内存模型
CAS
Volatile
AQS
synchronizatied和lock的区别
死锁的判断
currentHashMap的底层数据结构
并发程序中出现问题以及解决方案
场景问题
单点登录
权限认证是如何实现的
你负责的项目中遇到过什么棘手的问题,如何解决
公司日志是如何采集的
查看日志的命令有哪些
生产问题怎末排查
系统遇到瓶颈怎末解决