当前位置: 首页 > news >正文

徐汇专业做网站直接采用模板网站有什么缺点

徐汇专业做网站,直接采用模板网站有什么缺点,网站怎么做qq登录,网站开发软件技术开发公司JVM JVM是Java virtual machine#xff08;Java虚拟机#xff09;的缩写#xff0c;是一种用于计算机的规范#xff0c;是通过在实际计算机上仿真模拟各种计算机功能来实现的。 主要组件构成#xff1a; 1.类加载器 子系统负责从文件系统或者网络中加载Class文件…JVM JVM是Java virtual machineJava虚拟机的缩写是一种用于计算机的规范是通过在实际计算机上仿真模拟各种计算机功能来实现的。 主要组件构成 1.类加载器 子系统负责从文件系统或者网络中加载Class文件Class文件在文件开头有特定的文件标识ClassLoader只负责加载Class文件是否运行取决于ExecutionEngine。 2.执行引擎 执行字节码或者执行本地方法 3.内存管理系统 负责管理Java程序运行时的内存分配和回收包括堆、方法区等。 4.即时编译器 将频繁执行的字节码转换为本地机器代码以提高执行效率。 5.运行时数据区 包括方法区、堆、Java栈、程序计数器、本地方法栈。 jvm的内存结构堆内存、方法区、栈 1.堆内存heap Java堆Java Heap是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例几乎所有的对象实例都在这里分配内存。 2.方法区Method Area 方法区Method Area与Java堆一样是各个线程共享的内存区域它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。 3、程序计数器Program Counter Register 程序计数器Program Counter Register是一块较小的内存空间它的作用可以看做是当前线程所执行的字节码的行号指示器。 4、Java虚拟机栈JVM Stacks Java虚拟机栈Java Virtual Machine Stacks也是线程私有的它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型每个方法被执行的时候都会同时创建一个栈帧Stack Frame用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。 5、本地方法栈Native Method Stacks 本地方法栈Native Method Stacks与虚拟机栈所发挥的作用是非常相似的其区别不过是虚拟机栈为虚拟机执行Java方法也就是字节码服务而本地方法栈则是为虚拟机使用到的Native方法服务。 JVM内存分配机制 JVM内存≈Heap(堆内存)PermGen(方法区)Thrend(栈) Heap堆内存Young年轻代Old老年代官方文档建议整个年轻代占整个堆内存的3/8老年代占整个堆内存的5/8但是可以配置为其他比例。 Young年轻代EdenSpaceFromSurvivorToSurvivorEden区与两个存活区的内存大小比例是811同样可以配置为其他比例。 java代码如何被JVM执行的 java文件计算机是识别不了的所以首先我们写的代码需要从.java文件编译为.class文件.class是字节码文件里面都是一些字节码指令这样的字节码指令才是计算机可以识别的。 JVM垃圾回收机制 1、new出来的对象先放在Eden区Eden区放满后第一次触发Young GC垃圾回收把存活对象移到S1存活区。 2、第二次Eden区又满了再次触发Young GC把Eden区的存活对象移到S2存活区把S1存活区的存活对象也移到S2存活区这时S1存活区清空了。 3、第三次Eden区又满了再次触发Young GC把Eden区的存活对象移到S1存活区把S2存活区的存活对象也移到S1存活区这时S2存活区清空了。 4、这样S1和S2交替互换轮流为清空大大拉长了存活对象进入老年代的时间间隔。 类对象什么时候进入老年代    a、大对象直接进入老年代Eden区放不下直接进入老年代    b、长期存活的对象进入老年代以Young GC次数进行判断的默认次数15次后进入老年代   c、执行Young GC时存活区放不下时存活对象也直接进入老年代 5、一直这样循环往复直到老年代满了触发Full GC。首先清除老年代中的没有引用的对象再对Eden区进行GC还会对持久代进行GC持久代一般没什么可清理 6、老年代里面放满以后执行Full GC也释放不了内存空间就会报内存溢出的错误了。 总结 1、Young GC只发生在Eden区Eden区是整个Java堆内存分配的入口new对象优先分配到Eden区Eden区满之后触发Young GC 2、Young GC触发后然后它会判断Eden区的对象是否是存活的如果是存活的则放到存活区不是存活的则清除掉释放内存空间。 3、触发Full GC是虽然也清理了Eden区但是Young GC次数不会1它是Full GC在干活。 什么时候触发Full GC    a、老年代空间不足    b、持久代空间不足的时候也会触发Full GC    c、显示调用也可以触发Full GC比如说RunTime.GC、System.GC    d、RMI框架会产生大量的对象会进行显示调用触发Full GC    e、Young GC时的悲观策略dump live的内存信息时jmap-dump:live 4、执行Young GC和Full GC应用程序的所有线程都是暂停的、停止工作但Full GC时间比较长 5、JVM调优的核心思想    a、尽量减少Full GC的次数或者说延长Full GC间隔时间。不要频繁触发Full GC因为执行Full GC的时间比较长。    b、尽量减少Young GC执行的时间 回收算法 标记-清除算法 分为两个阶段标记和清除内存使用了一段时间之后里面肯定有垃圾对象也有正常对象第一个阶段进行标记就是把每个对象标记出是垃圾对象还是正常对象而具体判断依据就是上面的垃圾判断算法第二个阶段进行清除就是把所有垃圾对象进行清除 标记-清除算法适用于存活对象比较多的情况清除的对象越少效率就高缺点是清除之后会产生内存碎片随着多次垃圾回收多次标记-清除之后内存碎片现象会更加严重导致大对象找不到连续内存进行存放。  标记-复制算法 复制算法就是说有把内存划分为两块A块和B块第一次使用时比如说使用了B块就会只在B块中分配对象当进行垃圾回收的时候把B块中存活的对象全部复制出来然后放在A块里面清空B块垃圾回收之后进行第二次使用时使用A块依次往复 复制算法的适用于存活对象比较少的情况复制的对象越少效率就高缺点就是内存使用率不高因为始终有一块内存是闲置的。 标记-整理算法 分为两个阶段标记和整理内存使用了一段时间之后里面有垃圾对象和正常对象第一个阶段进行标记和标记-清除算法中的标记过程一样把每个对象标记出来是垃圾对象还是正常对象具体判断依据就是上面的垃圾判断算法第二个阶段进行整理就是把垃圾对象清理之后并且把存活对象进行内存整理整齐地在内存中排列 标记-整理算法同样适用于存活对象比较多的情况清除的对象越少效率就越高而且通过内存整理解决了内存碎片的问题但同时也意味着更慢了因为需要时间来进行内存整理。 分代收集算法 我们将内存区域分成两片一边叫新生代另一边叫老年代 并且引入一个属性年龄 我们将年龄定义为经历过多少次 GC且还存活的轮次例如经历 3 次 GC还健在的对象年龄为 3 新生代再分为伊甸区和两个幸存区然后每次新建立的对象都会放在伊甸区并且根据经验规律大部分对象连一轮 GC 都撑不过所以每次 GC 后伊甸区只会剩下小部分对象 然后将这部分对象通过复制算法移动到其中一个幸存区中再释放伊甸区的对象注意幸存区有两个可以方便复制算法在这两个区域运行 移动到幸存区后还会经历多次 GC每次 GC 运行后幸存的对象又会通过复制算法移动到另一个幸存区再将之前的幸存区释放 随后将幸存区中满足年龄要求的对象会通过复制算法移动到老年代 能够到达老年区也就足以说明这些对象在短时间内还死不了所以老年代中会进行频率更低的 GC如果老年代中发现了垃圾就会通过标记-整理算法清除。如果对象空间很大则会被直接移动到老年代中 垃圾收集器问什么时候下会触发gc GC是由JVM自动完成的根据JVM系统环境而定所以机制是不确定的当然我们也可以手动进行垃圾回收比如调用System.gc()方法通知JVM进行垃圾回收但是具体什么时候运行也是无法控制的也就是说我们调用了System.gc()只是通知JVM要去回收但是什么时候回收是由JVM决定的但是不建议手动调用该方法因为GC消耗的资源比较大。 那会触发垃圾回收的情况有以下几种 1.当Eden区或者S区不够用了 2.老年代空间不够用了 3.方法区空间不够用了 4.System.gc() 执行的是Full GC的操作 参考垃圾回收(GC) 很干,很全_gc垃圾回收_浩展的博客-CSDN博客 垃圾回收机制——GC详讲_gc回收机制_答辣喇叭的博客-CSDN博客 Redis redis是一款高性能的NOSQL系列的非关系型数据库 NoSQL(NoSQL Not Only SQL)意即“不仅仅是SQL”是一项全新的数据库理念泛指非关系型的数据库。 Redis是用C语言开发的一个开源的高性能键值对key-value数据库官方提供测试数据50个并发执行100000个请求,读的速度是110000次/s,写的速度是81000次/s 且Redis通过提供多种键值数据类型来适应不同场景下的存储需求目前为止Redis支持的键值数据类型如下                 1) 字符串类型 string                 2) 哈希类型 hash                 3) 列表类型 list                 4) 集合类型 set                 5) 有序集合类型 sortedset redis的数据结构 redis存储的是key,value格式的数据其中key都是字符串value有5种不同的数据结构 value的数据结构                     1) 字符串类型 string                     2) 哈希类型 hash map格式                       3) 列表类型 list linkedlist格式。支持重复元素                     4) 集合类型 set   不允许重复元素                     5) 有序集合类型 sortedset不允许重复元素且元素有顺序 Redis优缺点 优点 读写性能优异 Redis能读的速度是110000次/s写的速度是81000次/s。 支持数据持久化支持AOF和RDB两种持久化方式。 支持事务Redis的所有操作都是原子性的同时Redis还支持对几个操作合并后的原子性执行。 数据结构丰富除了支持string类型的value外还支持hash、set、zset、list等数据结构。 支持主从复制主机会自动将数据同步到从机可以进行读写分离。 缺点 数据库容量受到物理内存的限制不能用作海量数据的高性能读写因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。 Redis 不具备自动容错和恢复功能主机从机的宕机都会导致前端部分读写请求失败需要等待机器重启或者手动切换前端的IP才能恢复。 主机宕机宕机前有部分数据未能及时同步到从机切换IP后还会引入数据不一致的问题降低了系统的可用性。 Redis 较难支持在线扩容在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题运维人员在系统上线时必须确保有足够的空间这对资源造成了很大的浪费。 redis 五种数据结构对应的数据场景 1.String 字符串类型 String是redis中最基本的数据类型一个key对应一个value。 String类型是二进制安全的意思是 redis 的 string 可以包含任何数据。如数字字符串jpg图片或者序列化的对象。 这里稍微讲一下什么是二进制安全一个二进制安全功能函数其本质上将操作输入作为原始的、无任何特殊格式意义的数据流。对于每个字符都公平对待不特殊处理某一个字符。 什么意思呢举个例子 C语言中的字符串是根据特殊字符“\0”来判断该字符串是否结束对于字符串str0123456789\0123456789”来说在C语言里面str的长度就是10strlen(str)10所以strlen()函数不是二进制安全的。而在Redis中strlen str的结果是21是二进制安全的Redis底层所使用的字符串表示是Sds它只关心二进制化的字符串不关心字符串的具体格式里面有啥字符只会严格的按照二进制的数据存取不会以某种特殊格式解析字符串。 实战场景 1.缓存 经典使用场景把常用信息字符串图片或者视频等信息放到redis中redis作为缓存层mysql做持久化层降低mysql的读写压力。 举个我曾经做看守所项目时候使用过的例子做很多流程操作的时候比如家属会见、财务管理等等我们往往都会先判断当前人员是否为在押人员而判断是否为在押人员是另外一个微服务接口如果直接实时的去调用那个接口短时的高并发很有可能把这个服务也拖挂最终导致整个系统不可用并且 RPC 本身也是比较耗时的所以就考虑在这里进行优化。 那当时我们是怎么做呢很简单的一个思路提前将所有的在押人员的user_id存到redis中这样当请求到来的时候我们直接通过缓存可以快速判断是否为在押人员。如果不是则直接在这里返回前端。 通过预先处理减少了实时链路上的 RPC 调用既减少了系统的外部依赖也极大的提高了系统的吞吐量。 2.计数器redis是单线程模型一个命令执行完才会执行下一个同时数据可以一步落地到其他的数据源。一般会使用decr、incr命令用于计数器的实现。 当遇到需求在规定时间用户的访问量不能超过规定次数的时候就可以用redis中的计数器来实现了又可以使用这个技术用来做限流使用用户的ip作为key用户访问一次就加1如果超过次数就返回false可以处理业务上面的的一些访问次数之类的例如文章的点赞数阅读量允许有一点的延迟效果先保存到redis中然后在同步到数据库当中3.session常见方案spring session redis实现session共享 2.Hash 哈希 Hash是一个MapmapValue值本身又是一种键值对结构如 value{{field1,value1},…fieldN,valueN}} 实战场景 1.缓存 能直观相比string更节省空间一些可以维护缓存信息如用户信息视频信息等但用hash实现的string也可以实现。 为什么这么说呢 其实hash类型的(key、field、value)的结构与对象的(对象id属性值)的结构相似也可以用来存储对象。 所以hash也可以用stringjson存储对象的一种方式那么存储对象时到底用stringjson还是用hash呢 stringjson hash 效率 很高 高 容量 低 低 灵活性 低 高 序列化 简单 复杂 所以说当对象的某个属性需要频繁修改时不适合用stringjson因为不够灵活每次修改都需要重新将整个对象序列化并赋值如果使用hash类型则可以针对某个属性单独修改没有序列化也不需要修改整个对象。比如商品的价格、销量、关注数、评论数等可能经常发生变化的属性就适合存储在hash类型里面。 综上一般对象用stringjson存储对象中某些频繁变化的属性抽出来用hash存储。 2.购物车以用户id为key商品id为field商品数量为value恰好构成购物车的3个要素。 3.链表 List 说白了就是链表redis 使用双端链表实现的 List是有序的value可以重复可以通过下标取出对应的value值左右两边都能进行插入和删除数据。 实战场景 1.timeline例如微博的时间轴有人发布微博用lpush加入时间轴展示新的列表信息。 2.排行榜 list类型的lrange命令可以分页查看队列中的数据。可将每隔一段时间计算一次的排行榜存储在list类型中如京东每日的手机销量排行、学校每次月考学生的成绩排名。但是并不是所有的排行榜都能用list类型实现只有定时计算的排行榜才适合使用list类型存储与定时计算的排行榜相对应的是实时计算的排行榜list类型不能支持实时计算的排行榜 但是对于频繁更新的列表list类型的分页可能导致列表元素重复或漏掉。 举个例子当前列表里由表头到表尾依次有EDCBA五个元素每页获取3个元素用户第一次获取到EDC三个元素然后表头新增了一个元素F列表变成了FEDCBA此时用户取第二页拿到CBA元素C重复了。只有不需要分页比如每次都只取列表的前5个元素或者更新频率低比如每天凌晨更新一次的列表才适合用list类型实现。对于需要分页并且会频繁更新的列表需用使用有序集合sorted set类型实现。另外需要通过时间范围查找的最新列表list类型也实现不了也需要通过有序集合sorted set类型实现如以成交时间范围作为条件来查询的订单列表。 4.Set 集合 集合类型也是用来保存多个字符串的元素但和列表不同的是集合中 1. 不允许有重复的元素2.集合中的元素是无序的不能通过索引下标获取元素3.支持集合间的操作可以取多个集合取交集、并集、差集。跟Java的HashSet类似。 实战场景 1.标签tag,给用户添加标签或者用户给消息添加标签这样有同一标签或者类似标签的可以给推荐关注的事或者关注的人。 2.点赞或点踩收藏等可以放到set中实现 因为Redis为set类型提供了求交集并集差集的操作可以非常方便地实现譬如共同关注、共同爱好、共同好友等功能。 sinter交集命令可以获得A和B两个用户的共同好友sismember命令可以判断A是否是B的好友scard命令可以获取好友数量关注时smove命令可以将B从A的粉丝集合转移到A的好友集合srandmember命令可以随机展示当然黑名单白名单也一样set类型适合存储这些黑名单数据sismember命令可用于判断用户、ip、设备是否处于黑名单之中。 5.zset 有序集合 有序集合和集合有着必然的联系它和set一样是不可重复的区别在于多了score值用来代表排序的权重。也就是当你需要一个有序的不可重复的集合列表时就可以考虑使用这种数据类型。 有序集合中的元素不可以重复但是score 分数可以重复就和一个班里的同学学号不能重复但考试成绩可以相同。 实战场景 1.排行榜有序集合经典使用场景。例如小说视频等网站需要对用户上传的小说视频做排行榜榜单可以按照用户关注数更新时间字数等打分做排行。   使用redis做缓存的原因 高性能 redis是用C语言编写的稳定性和性能更好。 用户第一次访问数据库中的某些数据因为是从硬盘上读取的这个过程会比较慢。将该用户访问的数据存在redis缓存中这样下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存所以速度相当快。如果数据库中的对应数据改变的之后同步改变缓存中相应的数据即可 高可靠 支持集群模式和持久化等特性不会应为缓存量太多而导致虚拟机崩溃。Redis是独立部署的即使网站更新redis缓存的数据也不会消失。 高并发 直接操作缓存能够承受的请求是远远大于直接访问数据库的所以我们可以考虑把数据库中的部分数据转移到缓存中去这样用户的一部分请求会直接到缓存这里而不用经过数据库。 redis 高性能原理的原因 1、完全基于内存绝大部分请求是纯粹的内存操作非常快速。数据存在内存中类似于 HashMap HashMap 的优势就是查找和操作的时间复杂度都是O(1) 2、数据结构简单对数据操作也简单Redis 中的数据结构是专门进行设计的 合理的数据编码 对于每一种数据类型来说底层的支持可能是多种数据结构什么时候使用哪种数据结构这就涉及到了编码转化的问题。 那我们就来看看不同的数据类型是如何进行编码转化的 String存储数字的话采用int类型的编码如果是非数字的话采用 raw 编码 List字符串长度及元素个数小于一定范围使用 ziplist 编码任意条件不满足则转化为 linkedlist 编码 Hashhash 对象保存的键值对内的键和值字符串长度小于一定值及键值对 Set保存元素为整数及元素个数小于一定范围使用 intset 编码任意条件不满足则使用 hashtable 编码 Zsetzset 对象中保存的元素个数小于及成员长度小于一定值使用 ziplist 编码任意条件不满足则使用 skiplist 编码。 3、采用单线程避免了不必要的上下文切换和竞争条件也不存在多进程或者多线程导致的切换  而消耗CPU不用去考虑各种锁的问题不存在加锁释放锁操作没有因为可能出现死锁而导致的 性能消耗 4、使用多路 I/O 复用模型非阻塞 IO 5、使用底层模型不同它们之间底层实现方式以及与客户端之间通信的应用协议不一样Redis 直接自己构建了 VM 机制 因为一般的系统调用系统函数的话会浪费一定的时间去移动和请 求 redis 缓存 出现的缓存击穿、缓存雪崩、缓存穿透的具体解决方法 三者出现的根本原因Redis命中率下降请求直接打在DB上 正常情况下大量的资源请求都会被redis响应在redis得不到响应的小部分请求才会去请求DB这样DB的压力是非常小的是可以正常工作的如下图 如果大量的请求在redis上得不到响应那么就会导致这些请求会直接去访问DB导致DB的压力瞬间变大而卡死或者宕机。如下图 ① 大量的高并发的请求打在redis上 ② 这些请求发现redis上并没有需要请求的资源redis命中率降低 ③ 因此这些大量的高并发请求转向DB数据库服务器请求对应的资源 ④ DB压力瞬间增大直接将DB打垮进而引发一系列“灾害” 那么为什么redis会没有需要访问的数据呢通过分析大致可以总结为三种情况也就对应着redis的雪崩、穿透和击穿下文开始进行详解 问题名称 缓存穿透 缓存击穿 缓存雪崩 资源是否存在DB数据库服务器中 × √ √ 资源是否存在Redis中 × × × redis没有对应资源的原因 根本不存在该资源DB也没有 某个热点key过期 大部分key集体过期 根本原因 大量的高并发的请求打在Redis上但是发现Redis中并没有请求的数据redis的命令率降低所以这些请求就只能直接打在DB数据库服务器上在大量的高并发的请求下就会导致DB直接卡死、宕机。 1.缓存穿透 缓存穿透产生的原因请求根本不存在的资源DB本身就不存在Redis更是不存在这时的用户很可能是攻击者如发起为id为-1的数据或id为特别大不存在的数据导致数据库压力过大或宕机。 解决方式对空值进行缓存 类似于上面的例子虽然数据库中没有id-3872的用户的数据但是在redis中对他进行缓存key-3872valuenull这样当请求到达redis的时候就会直接返回一个null的值给客户端避免了大量无法访问的数据直接打在DB上 实时监控 对redis进行实时监控当发现redis中的命中率下降的时候进行原因的排查配合运维人员对访问对象和访问数据进行分析查询从而进行黑名单的设置限制服务拒绝黑客攻击 使用布隆过滤器 使用BitMap作为布隆过滤器将目前所有可以访问到的资源通过简单的映射关系放入到布隆过滤器中哈希计算当一个请求来临的时候先进行布隆过滤器的判断如果有那么才进行放行否则就直接拦截 接口校验 类似于用户权限的拦截对于id-3872这些无效访问就直接拦截不允许这些请求到达Redis、DB上。 注意事项 1).使用空值作为缓存的时候key设置的过期时间不能太长防止占用太多redis资源 2).使用空值作为缓存只能防止黑客重复使用相同的id暴力攻击但是如果黑客使用动态的无效id攻击就没有效果需要配合网警 3).使用布隆过滤器也是有哈希冲突的可能 2.缓存雪崩 缓存雪崩产生的原因redis中大量的key集体过期, 缓存集中过度或者缓存服务器宕机导致大量请求访问数据库造成数据库瞬间压力过大宕机。 解决方式将失效时间分散开 通过使用自动生成随机数使得key的过期时间是随机的防止集体过期 使用多级架构 使用nginx缓存redis缓存其他缓存不同层使用不同的缓存可靠性更强 设置缓存标记 记录缓存数据是否过期如果过期会触发通知另外的线程在后台去跟新实际的key 使用锁或者队列的方式 如果查不到就加上排它锁其他请求只能进行等待 3.缓存击穿 产生缓存雪崩的原因redis中的某个热点key过期但是此时有大量的用户访问该过期key,  高并发时当一个key非常热点类似于爆款在不停的扛着大并发当这个key在失效的瞬间持续的大并发就穿破缓存直接请求数据库并设置到缓存中导致性能下降。 解决方案提前对热点数据进行设置 类似于新闻、某博等软件都需要对热点数据进行预先设置在redis中 监控数据适时调整 监控哪些数据是热门数据实时的调整key的过期时长 使用锁机制 最后的防线当热点key过期那么就使用锁机制防止大量的请求直接打在DB 如何保证Redis与数据库的数据一致 ONE 案例 先删除“缓存”再去更新“数据库”。但是该方案还存在问题 在高并发情况下第一个线程删除缓存还没来得及去操作数据库这时第二个线程访问缓存发现为null于是去数据库查询获取到需要的值这时候第一个线程才开始操作数据库然后设置缓存但是第二个线程又跟奇怪的将第一个线程刚设置的缓存给覆盖掉然后就出现“乌龙”数据不一致的问题也出现了 解决方案 ① 先操作缓存去修改数据库但不删除缓存。将这个不删除的缓存设置为一个特殊值*123当客户端读缓存的时候发现有前缀包含( * ???知道他是坏值就会进行休眠1秒这样然后再去查询Redis。 //这样做的弊端是特殊值对业务可能出现影响休眠时间会重复高并发情况下修改操作频繁反复会修改这个特殊值的内容然后同时出现睡眠影响性能。 ②延迟双删先删除缓存数据再把数据更新到数据库中休眠一会根据业务逻辑的耗时更改休眠时间后再次删除该缓存数据。若线程1是更新请求线程2是查询请求延迟双删可以保证再这两个请求同时存在的情况下的数据一致性确保查询请求结束更新请求可以删除查询请求造成的缓存脏数据。 总结写操作不能太频繁 TWO 案例 先删除“数据库”再去更新“缓存”。 该案例的问题是数据库写完之后再删除缓存但删除失败了这会导致数据不一致。 解决方案 ①给缓存设置一个过期时间但缺点是过期时间内 不能保证数据是有用的数据可能是上次没删掉的坏数据。 ②引入MQ保证原子操作。 一个去删缓存一个去操作数据库。MQ若是删除操作失败了启动MQ重试机制在重试的这段时间缓存数据不会更新。 ③将热点数据缓存设置为永不过期但是在value当中写入一个逻辑上的过期时间另外起一个后台线程扫描这些key对于已逻辑上过期的缓存进行删除。 总结始终只能保证一定时间内的最终一致性。 THREE 案例 Redis和Mysql集群实现的读写分离架构 如果MySQL采用的是读写分离的架构主从服务器之间也会存在时间差也就是A更新操作删除缓存并请求主数据库进行数据更新主库与从库进行同步数据的操作B进行查询操作时缓存中没有数据就去从库中读取数据此时主从数据未更新完成拿到的还是旧数据。 解决方法是查询数据经过Redis时若查询缓存为空时强制将其指向主数据库中进行查询。 Four 案例 异步更新缓存(基于订阅binlog的同步机制) MySQL binlog增量订阅消费消息队列增量数据更新到redis 读Redis热数据基本都在Redis 写MySQL:增删改都是操作MySQL 更新Redis数据MySQ的数据操作binlog来更新到Redis Redis更新 ①数据操作主要分为两大块 一个是全量(将全部数据一次写入到redis) 一个是增量实时更新 这里说的是增量,指的是mysql的update、insert、delate变更数据。 ②读取binlog后分析 利用消息队列,推送更新各台的redis缓存数据。 这样一旦MySQL中产生了新的写入、更新、删除等操作就可以把binlog相关的消息推送至RedisRedis再根据binlog中的记录对Redis进行更新。 这种机制很类似MySQL的主从备份机制因为MySQL的主备也是通过binlog来实现的数据一致性。 这里可以结合使用canal(阿里的一款开源框架)通过该框架可以对MySQL的binlog进行订阅而canal正是模仿了mysql的slave数据库的备份请求使得Redis的数据更新达到了相同的效果。 参考redis常见面试题_鲨鱼辣椒_TUT的博客-CSDN博客 反射 1.反射是什么 反射Reflection能够让运行于 JVM 中的程序检测和修改运行时的行为。 JAVA反射机制是在运行状态中对于任意一个类都能够知道这个类的所有属性和方法对于任意一个对象都能够调用它的任意一个方法和属性这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象. 反射就是把java类中的各种成分映射成一个个的Java对象 例如一个类有成员变量、方法、构造方法、包等等信息利用反射技术可以对一个类进行解剖把个个组成部分映射成一个个对象。 2.反射机制有什么用  运行时动态获取类的信息在编写代码时对于类的信息是必须在编译时确定的但在运行时有时需要根据某些条件动态获取某个类的信息这时就可以使用Java中的反射机制。 动态生成对象反射机制可以在运行时生成对象这样就可以根据参数的不同动态的创建不同的类的实例对象。 动态调用方法通过反射机制可以调用类中的方法不论这些方法是否是公共的也不论这些方法的参数个数和类型是什么反射机制都具有这样的能力。 动态修改属性利用反射机制可以获取到类中的所有成员变量并可以对其进行修改。 实现动态代理利用反射机制可以实现代理模式通过代理对象完成原对象对某些方法的调用同时也可以在这些方法的调用前后做一些额外的处理。 3.反射的实现原理 调用反射的总体流程如下 1、当我们编写完一个Java项目之后每个java文件都会被编译成一个.class文件。 2、这些class文件在程序运行时会被ClassLoader加载到JVM中当一个类被加载以后JVM就会在内存中自动产生一个Class对象。 3、通过Class对象获取Field/Method/Construcor 我们一般平时是通过new的形式创建对象实际上就是通过这些Class来创建的只不过这个class文件是编译的时候就生成的程序相当于写死了给jvm去跑。 反射是什么呢当我们的程序在运行时需要动态的加载一些类这些类可能之前用不到所以不用加载到jvm而是在运行时根据需要才加载。 原来使用new的时候需要明确的指定类名这个时候属于硬编码实现而在使用反射的时候可以只传入类名参数就可以生成对象降低了耦合性使得程序更具灵活性。 4.java反射技术的应用场景 框架开发许多流行的Java框架比如Spring、Hibernate、Struts等都使用了反射机制以提供更灵活、可扩展的特性。 应用程序开发反射机制常常用于某些需要动态加载或访问类信息的应用程序中比如动态配置插件管理等。 单元测试JUnit测试框架中反射机制被广泛应用可以方便地创建测试对象和调用测试方法。 动态代理反射机制可以实现动态代理实现不改变原来代码的情况下对原来对象的方法进行增强。 JavaBean工具JavaBean工具中使用反射机制可以获取类的属性名、属性值、调用属性的setter和getter方法等信息方便进行对象的序列化与反序列化操作。 在我们平时的项目开发过程中基本上很少会直接使用到反射机制但这不能说明反射机制没有用实际上有很多设计、开发都与反射机制有关例如模块化的开发通过反射去调用对应的字节码动态代理设计模式也采用了反射机制还有我们日常使用的 SpringHibernate 等框架也是利用CGLIB 反射机制才得以实现下面就举例最常见的两个例子来说明反射机制的强大之处 JDBC 的数据库的连接 在JDBC 的操作中如果要想进行数据库的连接则必须按照以上的几步完成 通过Class.forName()加载数据库的驱动程序 通过反射加载前提是引入相关了Jar包通过 DriverManager 类进行数据库的连接连接的时候要输入数据库的连接地址、用户名、密码通过Connection 接口接收连接 public class ConnectionJDBC { /** * param args */ //驱动程序就是之前在classpath中配置的JDBC的驱动程序的JAR 包中 public static final String DBDRIVER com.mysql.jdbc.Driver; //连接地址是由各个数据库生产商单独提供的所以需要单独记住 public static final String DBURL jdbc:mysql://localhost:3306/test; //连接数据库的用户名 public static final String DBUSER root; //连接数据库的密码 public static final String DBPASS ; public static void main(String[] args) throws Exception { Connection con null; //表示数据库的连接对象 Class.forName(DBDRIVER); //1、使用CLASS 类加载驱动程序 ,反射机制的体现 con DriverManager.getConnection(DBURL,DBUSER,DBPASS); //2、连接数据库 System.out.println(con); con.close(); // 3、关闭数据库 } Spring 框架的使用 在 Java的反射机制在做基础框架的时候非常有用行内有一句这样的老话反射机制是Java框架的基石。一般应用层面很少用不过这种东西现在很多开源框架基本都已经封装好了自己基本用不着写。典型的除了hibernate之外还有spring也用到很多反射机制。最经典的就是xml的配置模式。 Spring 通过 XML 配置模式装载 Bean 的过程 将程序内所有 XML 或 Properties 配置文件加载入内存中Java类里面解析xml或properties里面的内容得到对应实体类的字节码字符串以及相关的属性信息使用反射机制根据这个字符串获得某个类的Class实例动态配置实例的属性 Spring这样做的好处是 不用每一次都要在代码里面去new或者做其他的事情以后要改的话直接改配置文件代码维护起来就很方便了有时为了适应某些需求Java类里面不一定能直接调用另外的方法可以通过反射机制来实现 模拟 Spring 加载 XML 配置文件 public class BeanFactory {private MapString, Object beanMap new HashMapString, Object();/*** bean工厂的初始化.* param xml xml配置文件*/public void init(String xml) {try {//读取指定的配置文件SAXReader reader new SAXReader();ClassLoader classLoader Thread.currentThread().getContextClassLoader();//从class目录下获取指定的xml文件InputStream ins classLoader.getResourceAsStream(xml);Document doc reader.read(ins);Element root doc.getRootElement(); Element foo;//遍历beanfor (Iterator i root.elementIterator(bean); i.hasNext();) { foo (Element) i.next();//获取bean的属性id和classAttribute id foo.attribute(id); Attribute cls foo.attribute(class);//利用Java反射机制通过class的名称获取Class对象Class bean Class.forName(cls.getText());//获取对应class的信息java.beans.BeanInfo info java.beans.Introspector.getBeanInfo(bean);//获取其属性描述java.beans.PropertyDescriptor pd[] info.getPropertyDescriptors();//设置值的方法Method mSet null;//创建一个对象Object obj bean.newInstance();//遍历该bean的property属性for (Iterator ite foo.elementIterator(property); ite.hasNext();) { Element foo2 (Element) ite.next();//获取该property的name属性Attribute name foo2.attribute(name);String value null;//获取该property的子元素value的值for(Iterator ite1 foo2.elementIterator(value); ite1.hasNext();) {Element node (Element) ite1.next();value node.getText();break;}for (int k 0; k pd.length; k) {if (pd[k].getName().equalsIgnoreCase(name.getText())) {mSet pd[k].getWriteMethod();//利用Java的反射极致调用对象的某个set方法并将值设置进去mSet.invoke(obj, value);}}}//将对象放入beanMap中其中key为id值value为对象beanMap.put(id.getText(), obj);}} catch (Exception e) {System.out.println(e.toString());}}//other codes }
http://www.zqtcl.cn/news/475768/

相关文章:

  • wordpress企业建站模版wordpress门户网站模板
  • 网站建设时间及简介企业注册代理
  • 网站首页制作方案wordpress中常用插件安装包
  • 阿里云建立网站赤坎网站建设公司
  • 时光轴 网站小公司做网站赚钱吗
  • 手机管理网站模板乐山住房和城乡建设厅网站
  • wordpress链接样式设置方法网络seo推广培训
  • 建站系统wordpress下载企业网站建设课程体会
  • 网站资源规划怎么写wordpress怎么解绑域名
  • 建湖企业做网站多少钱网页开发工具软件
  • WordPress怎么建小站wordpress替换谷歌字体库
  • ps建设网站步骤佛山做外贸网站特色
  • 杭州做代发的网站有哪些计算机基础网站建设和网络安全
  • 做汽配外贸是在哪个网站做山东百度推广
  • 网站类型大全cms监控软件下载官网
  • 网站设计制作 建网站免费asp地方门户网站系统
  • 凡科网做的网站保存后就上传了吗东莞网站推广建设
  • 网站推广案例闲鱼上做网站
  • 网站 做购物车分类信息网站建设系统
  • 网站做弹窗坂田建设网站
  • 北仑网站推广保险网站建设
  • 文山城乡建设部网站首页个人网站怎么注册
  • 西安企业建站wordpress外部调用后台
  • 江苏手机网站建设公司域名查询ip解析
  • 网站上的用户注册怎么做的苏州网站建设制作服务商
  • 网站开发模版宁波网
  • 以鹦鹉做头像的网站wordpress post是什么
  • 公司怎么建立自己网站做网站需要编码吗
  • 网站域名根目录在哪里wordpress做跟随导航导航
  • 昆明网站建站推广it外包工作怎么样