-
使用Redis作为缓存需要注意些什么
数据一致性的问题
单个数据库在多线程操作的时候如果不是数据库锁的限制会出现很多数据不一致的问题,ACID(原子性、一致性、隔离性和持久性)。
redis缓存也会有这样的问题,就是数据库的数据更新到redis是会有时间差的,这样的时间差就会导致数据不一致。
策略:
不要缓存那些对于数据一致性要求很高的数据,如果这个数据存在被修改的可能性,那么最好不要存缓存,要么,就不要放数据库,只放缓存
如果这个数据放了,但是对于这个数据的操作不是修改,而是只有删除的话,也是可以存放缓存的,因为在实际操作中,如果一个删除操作被执行的时候,缓存可以先进行删除,这样就能确保没有用户能够读取到删除之后的数据,然后再对数据库进行删除。
-
对缓存击穿的理解
引申其它的一起总结:实际操作理解的可参考:https://www.cnblogs.com/jay-wu/p/10782801.html
缓存穿透:当一个请求从缓存中取数据时,如果请求的key在缓存中不存在,就会跳过缓存,直接请求数据库,如果数据库中也不存在就会返回null,null是不会写入缓存的,多次请求,就会造成缓存穿透。
解决方案:返回空值也存入缓存中,并设置过期时间(比如设置为60秒),不过要考虑到过多的空值的键造成的影响
缓存雪崩:缓存服务器宕机,所有请求全部落到数据库上,导致数据库挂掉了。此时,就算是重启数据库,马上还会被新的请求给干掉。这就是缓存雪崩。
解决方案:(比较不通俗)
雪崩前:redis设计成高可用,防止大面积故障,如 Redis Sentinel 和 Redis Cluster
雪崩时:缓存限流、降级
雪崩后:redis持久化,快速备份和恢复数据
通俗的,比如在做电商项目的时候,一般是采取不同分类商品,缓存不同周期。在同一分类中的商品,加上一个随机因子。这样能尽可能分散缓存过期时间,而且,热门类目的商品缓存时间长一些,冷门类目的商品缓存时间短一些,也能节省缓存服务的资源---应该算是雪崩前的处理
缓存击穿:某个key访问非常频繁,处于集中式高并发的访问状态,当这个key在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库
解决方案:
(1)将高访问量的数据设置为永不过期;(2)实现互斥锁,待一个请求构建完释放锁后,其他请求再进行访问(大道至简,mutex key互斥锁真心用不上)。
-
Spring IOC原理
通俗解释得很好的:https://www.cnblogs.com/superjt/p/4311577.html
-
Spring是怎么实现的IOC
可以把IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言的的反射编程,根据配置文件中给出的类名生成相应的对象。从实现来看,IOC是把以前在工厂方法里写死的对象生成代码,改变为由配置文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性
有关反射的概念和用法,通俗来讲就是根据给出的类名(字符串方式)来动态地生成对象。这种编程方式可以让对象在生成时才决定到底是哪一种对象
-
Java 8对HashMap有哪些优化
1.对数据结构做了进一步的优化,增加了红黑树部分
2.扩充HashMap的时候,不需要像JDK1.7的实现那样重新计算hash,只需要看看原来的hash值新增的那个bit是1还是0就好了,是0的话索引没变,是1的话索引变成“原索引+oldCap”
既省去了重新计算hash值的时间,而且同时,由于新增的1bit是0还是1可以认为是随机的,因此resize的过程,均匀的把之前的冲突的节点分散到新的bucket了。这一块就是JDK1.8新增的优化点。有一点注意区别,JDK1.7中rehash的时候,旧链表迁移新链表的时候,如果在新表的数组索引位置相同,则链表元素会倒置
扩容(resize)就是重新计算容量,向HashMap对象里不停的添加元素,而HashMap对象内部的数组无法装载更多的元素时,对象就需要扩大数组的长度,以便能装入更多的元素。当然Java里的数组是无法自动扩容的,方法是使用一个新的数组代替已有的容量小的数组,就像我们用一个小桶装水,如果想装更多的水,就得换大水桶。
额外:
HashMap的容量为什么是2的n次幂,和这个(n - 1) & hash的计算方法有着千丝万缕的关系,符号&是按位与的计算,这是位运算,计算机能直接运算,特别高效,按位与&的计算方法是,只有当对应位置的数据都为1时,运算结果也为1,当HashMap的容量是2的n次幂时,(n-1)的2进制也就是1111111***111这样形式的,这样与添加元素的hash值进行位运算时,能够充分的散列,使得添加的元素均匀分布在HashMap的每个位置上,减少hash碰撞