redis
未读在redis中提供了俩种数据持久化的方式:1.RDB 2.AOF
1.RDB持久化
RDB全称Redis Database Backup file(redis 数据备份文件),也叫redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当redis实例故障重启后,从磁盘读取快照文件,恢复数据。
1.主动备份方式:执行命令
2.修改配置文件redis.conf 开启备份
1.1RDB的执行原理
bgsave开始时会fork(克隆)主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入RDB文件。
因为所有的进程无法直接操作物理内存,所以由操作系统给每个进程分配一个虚拟内存,每个进程只能操作自己的虚拟内存,操作系统会维护一个虚拟内存到物理内存的映射关系表,称作页表。
如果此时子进程在写RDB文件的时候主进程得到用户的请求在修改物理内存数据,此时可能会出现一些脏数据,为了避免这种情况发生,fork底层采用了copy-on-write技术:
当主进程执行读操作时候,访问共享内存
当主进程执行写操作时候,则会拷贝一份数据,执行写操作
2.AOF持久化 ...
redis
未读1.针对读场景
如果 Redis 中存在用户所需数据,直接返回。
如果 Redis 中不存在数据,从数据库中读取数据,并将其更新到 Redis 中,避免下次再次查询或其他用户查询时仍从数据库读取。
在高并发场景下,多个请求同时请求 Redis,发现数据不存在后,都会从数据库加载数据,然后重新将数据写入 Redis。这不会导致数据不一致的问题。
2.针对写场景
如果redis中本身不存在缓存数据,则直接修改db中的数据即可,不会产生数据不一致问题。
如果redis中已存在缓存数据,则需要同时修改db和redis中的数据,但是二者修改操作的执行必然存在先后顺序。在高并发的场景下,就有可能产生数据不一致的情况。
那么针对此中数据不一致问题,就产生了以下两个疑问:
由于redis中的数据可有可无,那么当数据发生变化时,是对redis中的数据进行修改,还是直接删除对应的redis,然后通过后续的读请求再回源db,将数据重新写入redis呢?
redis和db的数据写操作的顺序问题,是先更新redis,还是先更新db?
2.1 删缓存 or 更新
删缓存策略
优点:操作简单,直 ...
redis
未读1.基本原理
分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。
分布式锁的核心思想就是让大家都使用同一把锁,只要大家使用的是同一把锁,那么我们就能锁住线程,不让线程进行,让程序串行执行,这就是分布式锁的核心思路
那么分布式锁他应该满足一些什么样的条件呢?
可见性:多个线程都能看到相同的结果,注意:这个地方说的可见性并不是并发编程中指的内存可见性,只是说多个进程之间都能感知到变化的意思
互斥:互斥是分布式锁的最基本的条件,使得程序串行执行
高可用:程序不易崩溃,时时刻刻都保证较高的可用性
高性能:由于加锁本身就让性能降低,所有对于分布式锁本身需要他就较高的加锁性能和释放锁性能
安全性:安全也是程序中必不可少的一环
2.实现方式
常见的分布式锁有三种
Mysql:mysql本身就带有锁机制,但是由于mysql性能本身一般,所以采用分布式锁的情况下,其实使用mysql作为分布式锁比较少见
Redis:redis作为分布式锁是非常常见的一种使用方式,现在企业级开发中基本都使用redis或者zookeeper作为分布式锁,利用setnx这个方法,如果插入key成功,则表示获得到了 ...
redis
未读什么是缓存雪崩?
缓存雪崩是缓存中大量的key失效或者Redis服务宕机后当高并发到来时候导致大量请求到数据库,瞬间耗尽数据库资源,导致数据库奔溃。
造成缓存雪崩问题的原因是大量key拥有了相同的过期时间。当大量的key在同一时间过期失效后就会发生大量的请求到数据库。导致缓存雪崩。
如何解决缓存雪崩?
1.大量key失效
1、使用同步锁控制查询数据库的线程
使用同步锁控制查询数据库的线程,只允许有一个线程去查询数据库,查询得到数据后存入缓存。
Java synchronized(obj){ //查询数据库 //存入缓存 }
2、对同一类型信息的key设置不同的过期时间(TTL)
通常对一类信息的key设置的过期时间是相同的,这里可以在原有固定时间的基础上加上一个随机时间使它们的过期时间都不相同。
示例代码如下:
Java //设置过期时间300秒 redisTemplate.opsForValue().set(“course:” + courseId, JSON.toJSONString(coursePublish),300+new Rando ...
redis
未读1.什么是缓存击穿
缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。
常见的解决方案有两种:
互斥锁
逻辑过期
分析:假设线程1在查询缓存之后,本来应该去查询数据库,然后把这个数据重新加载到缓存的,此时只要线程1走完这个逻辑,其他线程就都能从缓存中加载这些数据了。但是往往操作数据库所花费的时间远远大于查询缓存锁需要的时间,所以当在线程1没有走完的时候,后续的线程2,线程3,线程4同时过来访问当前这个方法, 那么这些线程都不能从缓存中查询到数据(因为此时缓存重建并没有完成),那么他们接着同一时间去访问数据库,同时的去执行数据库代码,对数据库访问压力过大。
2.如何解决
2.1互斥锁
因为锁能实现互斥性。假设线程过来,只能一个人一个人的来访问数据库,从而避免对于数据库访问压力过大,但这也会影响查询的性能,因为此时会让查询的性能从并行变成了串行,我们可以采用tryLock方法 + double check来解决这样的问题。
假设现在线程1过来访问,他查询缓存没有命中,但是此时他获得到了锁的资源, ...
redis
未读1.什么是缓存穿透
缓存穿透 :**缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。**可能是恶意用户伪造不存在的id发起请求,会导致缓存和数据库都无法查到,导致所有请求打到数据库上,数据库可能会因为扛不住压力而挂掉。
2.解决方案
常见的解决方案有两种:
缓存空对象
优点:实现简单,维护方便
缺点:
额外的内存消耗
可能造成短期的不一致
布隆过滤
优点:内存占用较少,没有多余key
缺点:
实现复杂
存在误判可能
2.1缓存空对象
**缓存空对象思路:**当我们客户端访问不存在的数据时,先请求redis,但是此时redis中没有数据,此时会访问到数据库,但是数据库中也没有数据,这个数据穿透了缓存,直击数据库,我们都知道数据库能够承载的并发不如redis这么高,如果大量的请求同时过来访问这种不存在的数据,这些请求就都会访问到数据库,简单的解决方案就是哪怕这个数据在数据库中也不存在,我们也把这个数据存入到redis中去,这样,下次用户过来访问这个不存在的数据,那么在redis中也能找到这个数据就不会进 ...
线程的常用方法
Thread 类 API:
方法
说明
public void start()
启动一个新线程,Java虚拟机调用此线程的 run 方法
public void run()
线程启动后调用该方法
public void setName(String name)
给当前线程取名字
public void getName()
获取当前线程的名字线程存在默认名称:子线程是 Thread-索引,主线程是 main
public static Thread currentThread()
获取当前线程对象,代码在哪个线程中执行
public static void sleep(long time)
让当前线程休眠多少毫秒再继续执行Thread.sleep(0) : 让操作系统立刻重新进行一次 CPU 竞争
public static native void yield()
提示线程调度器让出当前线程对 CPU 的使用
public final int getPriority()
返回此线程的优先级
public final void ...
项目打包类型:
123<!-- <packaging>pom</packaging>--><!-- <packaging>jar</packaging>--> <packaging>war</packaging>
指定打包类型用标签,默认是jar类型
注意:什么时候会用到pom打包类型
pom的意思是项目里没有java代码,也不执行任何代码,只是为了聚合工程或传递依赖用的。所以并不会寻找配置文件,若想配置文件生效,改为jar
maven 默认的打包类型为 jar,在项目聚合的时候,需要显式的将 父项目的 packing 指定为 pom,然后再指定所属的子模块
如果没有将packing 指定为pom ,那么子模块之间将无法正常的进行依赖传递。我们执行的maven命令的时候将首先对父项目执行,而后当 父项目 的packing 类型为 pom 时,将对所有的子模块执行同样的命令,否则将无法执行同样的命令,那么依赖的传递将无法由maven 编译或者打包命令 得以执行。
所以在使用m ...
一、java中的各种锁
1.乐观锁
乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作。
java 中的乐观锁基本都是通过 CAS 操作实现的,CAS 是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败。
2.悲观锁
悲观锁是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会 block 直到拿到锁。java中的悲观锁就是Synchronized,AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到,才会转换为悲观锁,如 RetreenLock。
3.非公平锁
JVM按随机、就近原则分配锁的机制称为非公平锁,比如synchronized,而ReentrantLock 在构造函数中提供了是否公平锁的初始化方式,默认为非公平锁。非公平锁实 ...
Spring
未读
在方法中捕获异常并没有抛出去
spring控制事务是基于AOP机制,基于AOP的环绕通知的方式,如果方法抛出了异常给Spring框架,就会进行事务回滚,如果我们利用try…catch捕获了异常,异常不会抛出,也就不会进行事务回滚。
非事务方法调用事务方法
在非事务方法内部调用事务方法,尽管这个方法上面加了@Transactional 注解开启了事务,但因为并不是代理对象调用此方法,而是直接调用了 this 对象的方法,所以事务也会失效。因为spring是通过aop的方式,对需要spring管理事务的bean生成了代理对象,然后通过代理对象拦截了目标方法的执行,在方法前后添加了事务的功能,所以必须通过代理对象调用目标方法的时候,事务才会起效。
假设有一个UserService类,其中包含一个事务方法saveUser()和一个非事务方法updateUser():
12345678910111213141516@Servicepublic class UserService { @Autowired private UserMapper userMapper; ...