做生存分析的网站,网络营销课程个人总结范文,做网站需要参考书目书,手机 网站制作Java面试题总结2023 基础String中常用的方法 与 equals的区别值传递和引用传递数组和集合的区别成员变量和局部变量的区别final和finally和finalize的区别Cookie和Session的的区别接口分类接口和抽象类的区别说说你对抽象类的理解String/StringBuffer/StringBuilderjdk1.8的新特… Java面试题总结2023 基础String中常用的方法 与 equals的区别值传递和引用传递数组和集合的区别成员变量和局部变量的区别final和finally和finalize的区别Cookie和Session的的区别接口分类接口和抽象类的区别说说你对抽象类的理解String/StringBuffer/StringBuilderjdk1.8的新特性Java的基本数据类型java中异常分为那些种类 集合java中的集合有哪些Java中ArrayList和Linkedlist区别HashMap底层原理hashmap和hashtable的区别hashmap传送门 JVM介绍一下JVMJava类的加载机制垃圾回收机制java 的GC 什么时候回收拦击jvm的内存模型内存泄漏 多线程线程和进程线程的创建方式线程创建方式的区别wait()yield和sleep()的区别说说你对线程池的理解线程池的应用场景线程池的优势线程池的使用线程池的执行原理Java线程具有五中基本状态是那些 Mysqlsql执行慢的原因表设计三范式mysql的数据类型mysql搜索引擎数据库的隔离级别mysql的优化分库分表搭建mycat的核心配置文件主从复制读写分离.主从实现方式读写分离的实现方式 索引放弃索引优化数据库为什么使用B树而不是B树索引设计的原则事务的隔离级别mysql的锁有哪些什么是乐观锁和悲观锁?主键索引和唯一索引有啥区别 RedisRedis缓存预热Redis 是单线程的么线程安全么?redis传送门 MQMQ消息中间件的作用为什么要用消息中间件如何保证MQ消息不丢失如何解决数据丢失的问题如何确保消息正确的发送到MQ?如何避免消息重复投递或重复消费使用MQ的优点和缺点是什么使用MQ的场景能举例说一些么activeMQ和rabbitMQ有什么区别RabbitMQ 宕机了怎么处理 SpringSpringmvc 的运行原理Spring中的设计模式有哪些简单介绍一下Spring bean 的生命周期spring有哪些核心组件#{}和${}的区别是什么IOC/DI 的区别分布式ID生成解决方案 ES为什么要使用Elasticsearch?ES的应用场景 微服务Spring是一个生态体系Spring的常用注解Springboot注解Springboot自动装配NacosRibbon负载均衡Spring Cloud项目中用到哪些组件Feign的工作原理? 服务部署说下Linux常用命令 基础
String中常用的方法 split()分割toString()获取出字符串的内容charAt()获取指定索引处的字符equals():判断两个字符串内容是否相等substring():截取getBytes():将字符串转成字节数组valueOf():将数据转成字符串 trim():去除两端空格compareTo():按照字典顺序比较字符串与 equals的区别
比较基本数据类型的值是否相等比较引用数据类型的地址值是否相等, equals本来是比较引用数据类型的地址可以重写此方法比较对象的属性是否相等。
值传递和引用传递
值传递就是传递的过程中传递的是值对值操作之后不会影响原有变量的值 引用传递就是传递的过程中传递的是引用操作引用之后会影响原有变量的值
数组和集合的区别
长度区别: 数组的长度是固定的而集合的长度是可变的 ·存储数据类型的区别: 数组可以存储基本数据类型 , 也可以存储引用数据类型; 而集合只能存储引用数据型 内容区别: 数组只能存储同种数据类型的元素 ,集合可以存储不同类型的元素
成员变量和局部变量的区别
在类中的位置不同 成员变量在类中方法外 局部变量在方法定义中或者方法声明上 在内存中的位置不同 成员变量在堆内存 局部变量在栈内存 ·生命周期不同 成员变量随着对象的创建而存在随着对象的消失而消失 局部变量随着方法的调用而存在随着方法的调用完毕而消失 初始化值不同 成员变量有默认初始化值 局部变量没有默认初始化值必须定义赋值然后才能使用。
final和finally和finalize的区别
final 是最终的不可变的。修饰类该类不能被继承修饰 方法方法不能被重写修饰变量变量变成常量。 finally try…catch的异常处理中里面是必定会执行的代码一般用于资源释放。 finalize 是Object类中的一个方法当垃圾回收器确定不存在, 对该对象的更多引用时由对象的垃圾回收器调用此方法。
Cookie和Session的的区别
1、数据存储位置cookie数据存放在客户的浏览器上session数据放在服务器上。 2、安全性cookie不是很安全别人可以分析存放在本地的cookie并进行cookie欺骗考虑到安全应 当使用session。 3、服务器性能session会在一定时间内保存在服务器上。当访问增多会比较占用你服务器的性能 考虑到减轻服务器性能方面应当使用cookie。 4、数据大小单个cookie保存的数据不能超过4K很多浏览器都限制一个站点最多保存20个cookie。 5、信息重要程度可以考虑将登陆信息等重要信息存放为session其他信息如果需要保留可以放在 cookie中。
接口分类
1普通接口 2函数式接口接口内部有 且只有一个抽象方法。 3标记型接口接口内没有方法它的目的就是为了声明某些东西例如serializable
接口和抽象类的区别
构造方法 接口没有构造方法 抽象类有构造方法用于子类访问父类成员时给父类成员初始化。 成员方法 接口只能有抽象方法,1.8以后可以有默认方法 抽象类可以由抽象方法和普通方法 成员变量 接口只能是静态常量 抽象类可以是常量也可以是变量。
说说你对抽象类的理解
1. 抽象类大部分使用场景和普通类并没有太大区别比如成员变量、成员方法构造方法,
2. 抽象类通过abstract修饰抽象类中不一定有抽象方法但有抽象方法的类一定是抽象类
3. 抽象类不能实例化可以通过子类继承抽象类实例化子类
4. 抽象类主要用于公共方法的抽取便于子类继承父类后重写这些公共的方法
5.子类继承抽象类或实现接口必须重写父类或接口中的抽象方法除非子类也是抽象类String/StringBuffer/StringBuilder
String是不可变的stringbuffer 和builder 是字符串可变。StringBuffer和StringBuilder都继承了AbstractStringBuilder buff 方法中加了同步锁线程是安全的builder 没有加同步锁线程是不安全的在内存中的存储方式与String相同都是以一个有序的字符序列char类型的数组在jdk9当中将char 数组换成了 byte 数组进行存储不同点是StringBuffer/StringBuilder对象的值是可以改变的并且值改变以后对象引用不会发生改变 操作少量的字符串用String 单线程的情况下操作的大量的字符串用Stringbuilder,在多线程的情况下用StringBuffer。
jdk1.8的新特性
1.新增lamda表达式这块遍历集合以及定义匿名函数 2.switch中的变量可以是string类型之前只能是基本数据类型 3.增加流式编程让我们用stream的方式可以非常方便的对集合里的数据操作 4.新的时间类LocalDate、LocalTime、LocalDateTime这几个类让我们操作日期的时候非常方便 5.Java 8允许我们给接口添加一个非抽象的方法实现只需要使用 default关键字就行了
Java的基本数据类型
Java的类型分为四类八种 四类为整型浮点型布尔型字符型 基本数据类型有8种分别是byte、short、int、long 、float、double、char、boolean 对应包类Byte,Short,Integer,Long,Float,Double,Character,Boolean
java中异常分为那些种类
1、Error重大的问题我们处理不了。也不需要编写代码处理。比如说内存溢出。 2、Exception:一般性的错误是需要我们编写代码进行处理的。 (1)RuntimeException运行时异常。 (2)NullPointerException空指针异常最常遇到 (3)ArrayIndexOutOfBoundsException 下标越界异常 (4)IndexOutOfBoundsException 索引越界异常。当访问某个序列的索引值小于0或大于等于序列大小时抛出该异常。 (5) SQLException sql异常 (6)检查异常/编译异常 、 对于检查的异常必须处理可以采用捕获或抛出式解决 (7)ClassNotFoundException 类找不到异常 (8)FileNotFound 文件找不到异常在文件操作的时候一不小心路径写错了或者是windows切换linux的时候因为路径格式不一致经常会有这个错误 (9)ParseException解析异常一般当日期字符串解析时与指定格式不一致就是出现这个问题
集合
java中的集合有哪些
List中有 ArrayList:底层实现是数组查询快增删慢线程不安全效率高每次扩容为当前容量的1.5倍1 Vector:底层实现是数组查询快增删慢线程安全效率低扩容机制为翻倍 LinkedList:底层实现是双向链表增删快查询慢线程不安全效率高 Set 中有 HashSet:无序不可重复,底层使用Hash表实现存取速度快。 LinkedHashSet:采用hash表存储使用双向链表记录插入顺序 Map中有 HashMap、key重复则覆盖原有的value底层使用数组链表实现jdk1.8以后加入了红黑树线程不安全key和value都允许为null HashTable:key重复则覆盖原有的value底层使用数组链表实现jdk1.8以后加入了红黑树线程安全key和value都不允许为null
Java中ArrayList和Linkedlist区别
相同点 1、都是List 接口的实现类具有元素可重复存取有序特点 2、都是线程不安全效率高 不同点 1、数据结构ArrayList底层是动态数组LinkedList底层是双向链表 2、随机访问效率ArrayList效率优先于LinkedList 因为LinkedList 是线性的数据存储方式指针从前往后依次查询。 3、增加和删除效率LinkedList效率优先于ArrayList 因为ArrayList 增删操作要影响数组内的其他数据的下标。
HashMap底层原理
1在jdk1.8中 底层是数组 链表 红黑树实现 在Hashmap中初始化长度为16当用put方法存储数据时传入key及value值 此时将key值进行hash运算后的hash值作为entry键值对在数组中的索引位置确定位置之后首先判断该位置是否为空如果为空就将entry值放在该位置否则将entry以链表的方式存在数组中当链表长度超过8位之后会将链表转换为红黑树继续存储entry。 2在jdk1.8之前底层是通过数组链表实现的当我们创建hashmap时会先创建一个数组。 当我们用put方法存数据时先根据key的hashcode值计算出hash值然后用这个哈希值确定在数组中的位置再把value值放进去如果这个位置本来没放东西就会直接放进去如果之前就有就会生成一个链表把新放入的值放在头部。 当用get方法取值时会先根据key的hashcode值计算出hash值确定位置再根据equals方法从该位置上的链表中取出该value值。 当容量超过当前容量的0.75倍之后就会自动扩容为原来容量的2倍。这个0.75就是负载因子。 但是在jdk1.8之后最大的不同就是其由 数组链表 红黑树组成。因为在1.7的时候这个链表的长度不固定所以如果key的hashcode重复之后 那么对应的链表的数据的长度就无法控制了get数据的时间复杂度就取决于链表的长度了为了提高这一部分的性能 加入了红黑树如果链表的长度超过8位之后会将链表转换为红黑树极大的降低了时间复杂度
HashMap 线程不安全有多个线程同时 HashMap可能会导致数据的不一致。如果需要满足线程安全可以使用 ConcurrentHashMap。
hashmap和hashtable的区别
相同点 1、都是key-value 的双列集合 2、都是数组链表的底层原理 3.都实现了Map 接口。 不同点 1、继承的父类不同 Hashtable 继承Dictionary类而HashMap 继承Abstract Map类。 2、线程安全性不同 hashMap 允许null键和null值为空线程不同步不安全效率高hashtable 不允许null键和null 值线程同步安全效率低。 在java 开发中常用的是HashMap 类比如ConcurrentHashMap可以实现线程安全Hashtable 和vector 一样成为了废弃类。
hashmap传送门
JVM
介绍一下JVM
VM主要包括类加载器、执行引擎、本地接口、运行时数据区 类加载器加载类文件到内存。只管加载只要符合文件结构就加载 执行引擎负责解释命令 本地接口本地接口的作用是融合不同的语言为java所用。 JVM的运行时数据区分为五个区域堆、栈、本地方法栈、方法区、计数器。 计数器这里记录了线程执行的字节码的行号。 栈每个方法执行的时候都会创建一个栈用于存放 局部变量表、动态链接。 本地方法栈与栈类似是执行本地方法。 堆堆就是存放对象实例几乎所有的对象实例都在这里分配内存。 方法区用于存储Java虚拟机加载的类信息、常量、静态变量、以及编译器编译后的代码等数据。
Java类的加载机制
加载 Classloader通过完全限定名查找字节码文件并利用字节码文件创建一个class对象. 验证 确保class文件所包含的字节流信息符合当前虚拟机的要求不会对虚拟机造成自身安全主要包括四种验证 字节码 元数据 符号引用 文件格式验证 准备 在方法区中为类变量分配内存并设置初始值。实例变量不会在这里分配初始化而是随着对象分配到Java堆中。给静态变量分配内存空间 解析 将常量池中的符号引用替换成直接引用 初始化 如果有父类就对父类进行初始化 给静态变量和静态代码库进行初始化工作。 内存优化以及垃圾回收 垃圾回收机制
垃圾收集器一般必须完成两件事检测出垃圾回收垃圾。 检测垃圾一般有以下几种方法引用计数法可达性分析算法。引用计数法给一个对象引用计数为0则当作垃圾处理。可达性分析算法以根集对象为起始点进行搜索如果有对象不可达的话即是垃圾对象。 处理垃圾有四种算法1标记-清除Mark-sweep分为两个阶段标记和清除。标记所有需要回收的对象然后统一回收。2复制Copying把内存空间划为两个相等的区域每次只使用其中一个区域。垃圾回收时遍历当前使用区域把正在使用中的对象复制到另外一个区域中。3 标记-整理Mark-Compact结合了“标记-清除”和“复制”两个算法的优点。也是分两阶段第一阶段从根节点开始标记所有被引用对象第二阶段遍历整个堆清除未标记对象并且把存活对象“压缩”到堆的其中一块按顺序排放。 4分代收集算法(当今最常用的方法) 分代的垃圾回收策略对不同生命周期的对象可以采取不同的收集方式以便提高回收效率。
java 的GC 什么时候回收拦击
1.执行到System.gc 的时候。 2.新生代对象晋升到老年代对象的时候老年代剩余的 空间低于新生代晋升老年代的速效率会触发老年代的回收 3.new 一个对象的时候新生代放不下直接发到老年代空间不够触发fullgc. 对象划分 年轻代是所有新对象产生的地方 年老代在年轻代中经历了N次回收后仍然没有被清除的对象就会被放到年老代中 持久代用于存放静态文件比如java类、方法等
jvm的内存模型
Java堆Heap,是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例我们创建的所有对象都在堆中 方法区Method Area各个线程共享的内存区域它用于存储已被虚拟机加载的类信息、常量、静态变量 程序计数器Program Counter Register,是一块较小的内存空间它的作用可以看做是当前线程所执行的字节码的行号指示器。 JVM栈JVM Stacks,也是线程私有的它的生命周期与线程相同。 本地方法栈Native Method Stacks为虚拟机使用到的Native方法服务。 内存优化1 内存溢出oom 程序运行时占用的内存超出系统分配的内存就会出现内存溢出 引发原因递归死循环大量内存泄露
内存泄漏
当对象销毁后gc在回收该实例的时候发现该实例的被其他对象持有引用导致不能被回收出现内存泄漏 1 内部类引发的内存泄漏 因为java当中内部类默认持有外部类的引用当外部类销毁后一旦gc回收该实例发现内部类持有他的引用而导致不能回收该实例出现内存泄漏的情况。 解决方法将内部类改为静态内部类因为静态内部类生命周期和进程一样长且不持有外部类不会影响外部类对象的回收 2 资源未关闭 Cursorstreamdatabase比如这些东西在使用完成后需要进行close或者Unbind处理以节省内存 3 线程导致的内存泄漏一般使用异步线程都会创建一个内部类对象而创建线程一般执行耗时任务所以这个内部类默认持有外部类的引用如果耗时任务在外部类销毁的时候未执行完成会因为持有外部类引用导致外部类不能被回收 内存抖动 内存抖动是由于短时间内有大量对象创建和销毁它伴随着频繁的GC。gc会频繁抢占cup资源影响其他线程的执行效率对象的销毁和创建操作的是堆内存堆内存也叫动态内存是一块不连续的内存区域如果频繁的创建和销毁会造成大量的内存碎片消耗程序性能 解决方案 · 尽量避免在循环体内创建对象或者在循环内进行字符串拼接。 · 对于能够复用的对象可以使用对象池将它们缓存起来。
多线程
线程和进程
进程系统进行资源分配和调度的一个独立单位 线程 是比进程更小的可独立运行的基本单位一般处于进程当中可以看做是轻量级的进程
线程的创建方式
继承thread重写run方法 实现runnable接口重写run方法 实现callable接口重写call方法相对runnable可以声明返回类型。
线程创建方式的区别
1 thread方式最为简单可以通过this获取当前线程但是因为继承了thread类不能在继承其他类了 2 runnable方式子类实现这个接口可以继承其他的类多个线程可以共享同一个target对象没有返回值。
wait()yield和sleep()的区别
sleep:属于thread类指定休眠时间不会释放锁到时间后会自动执行 yield:不指定时间礼让优先级高的线程执行也不会释放锁当别的线程执行完毕后如果没有优先级更高的线程需要执行继续执行当前线程否则继续抢占CPU资源。 Wait属于object类一般不指定时间释放锁需要通过调用notify或notifyall方法唤醒才能继续执行如果给wait设置了等待时间如果到时间还没有唤醒则会自动唤醒。
说说你对线程池的理解
线程池就是提前创建好若干个线程如果有任务需要进行处理的话线程池里面的线程就会去处理任务处理完成之后线程就不会消失而是等待一下一个任务由于创建和销毁的线程是消耗系统资源的所以当你频繁的创建和销毁的时候就需要考虑线程池来提升系统的性能。
线程池的应用场景
线程池的我做的第一个项目当时用线程池做过文件上传最近一次用线程池就是最近做过一个电网类项目我们对用户的内容搜索历史做了保存当用户搜索的内容为新内容时需要添加这个搜索记录但是搜索的记录如果之前是存在的需要对之前保存的记录进行更新而如果用户根据搜索历史再次搜索我们在更新记录的同时不能影响搜索结果的查询所以当时我们对记录新增及更新这个接口放到了线程池当中这个线程池是使用Java原生的threadPoolExcutor来实现的并对核心线程数、最大线程及维护时间进行了自定义。
线程池的优势
1.降低系统资源消耗通过重用已存在的线程降低线程创建和销毁造成的消耗 2.提高系统响应速度当有任务到达时无需等待新线程的创建便能立即执行 3.方便线程并发数的管控线程若是无限制的创建不仅会额外消耗大量系统资源更是占用过多资源而阻塞系统或oom等状况从而降低4.系统的稳定性。线程池能有效管控线程统一分配、调优提高资源使用率 5.更强大的功能线程池提供了定时、定期以及可控线程数等功能的线程池使用方便简单。
线程池的使用
创建线程池 ExecutorService service new ThreadPoolExecutor(…) 核心参数 corePoolSize核心线程数默认情况下核心线程一直存活在线程池中即便他们在线程池中处于闲置状态。除非我们将ThreadPoolExecutor的allowCoreThreadTimeOut属性设为true的时候这时候处于闲置的核心线程在等待新任务到来时会有超时策略这个超时时间由keepAliveTime来指定。一旦超过所设置的超时时间闲置的核心线程就会被终止 maximumPoolSize线程池中所容纳的最大线程数如果活动的线程达到这个数值以后后续的新任务将会被阻塞。包含核心线程数非核心线程数。 keepAliveTime非核心线程闲置时的超时时长对于非核心线程闲置时间超过这个时间非核心线程就会被回收。只有对ThreadPoolExecutor的allowCoreThreadTimeOut属性设为true的时候这个超时时间才会对核心线程产生效果 unit时间单位 workQueue线程池中保存等待执行的任务的阻塞队列 threadFactory为线程池提供新线程的创建 handler无法处理新任务的时候抛出异常(拒绝策略) 线程池的执行原理
①如果在线程池中的线程数量没有达到核心的线程数量这时候就回启动一个核心线程来执行任务。 ②如果线程池中的线程数量已经超过核心线程数这时候任务就会被插入到任务队列中排队等待执行。 ③由于任务队列已满会立即启动一个非核心线程来执行任务当然线程池里边目前的线程数量不能超过最大线程数 ④如果线程池中的数量达到了所规定的最大值那么就会拒绝执行此任务这时候就会调用RejectedExecutionHandler中的rejectedExecution方法来通知调用者。
Java线程具有五中基本状态是那些
新建状态 使用new关键字或thread类和子类创建一个线程对象后该线程对象处于新建状态并保持这个状态直到程序start这个线程 就绪状态 当线程对象调用了start方法之后 线程进入就绪状态 在就绪队列中等待jvm线程调度器的调度 运行状态 如果就绪状态线程获得cpu资源后 就可以执行run方法 然后线程就进入运行状态 处于运行状态的线程及其复杂 它可以变为 阻塞状态 死亡状态 就绪状态 阻塞状态 如果一个线程执行了sleep suspend方法 失去所有资源后 线程进入阻塞状态 时间过了之后 获得设备资源的线程可重新进入就绪状态 死亡状态 一个运行状态的线程完成任务或终止条件发生 线程进入死亡状态 terminated执行完成。
Mysql
sql执行慢的原因
1.硬件问题。如网络速度慢内存不足I/O吞吐量小磁盘空间满了等。 2.没有索引或者索引失效。 3.数据过多可以通过分库分表解决
表设计三范式
第一范式每个列都不可以再拆分。 第二范式在第一范式的基础上非主键列完全依赖于主键而不能是依赖于主键的一部分。 第三范式在第二范式的基础上非主键列只依赖于主键不依赖于其他非主键。 在设计数据库结构的时候要尽量遵守三范式如果不遵守必须有足够的理由。比如性能。事实上我 们经常会为了性能而妥协数据库的设计。
mysql的数据类型
varchar,double,int,tynyint,smallint,mediumint,date,time,datetime,timestamp,text,longtext
mysql搜索引擎
MyISAM、InnoDB、BDB、MEMORY等对于 MySQL 5.5 及更高版本默认的存储引擎是 InnoDB。在 5.5 版本之前MySQL 的默认存储引擎是 MyISAM
• InnoDB 存储引擎 o 支持自增长列auto_increment自增长列的值不能为空如果在使用的时候为空的话就会从现有的最大值自动1如果有但是比现在的还大则就保存这个值。 o 支持外键foreignkey外键所在的表称为子表而所依赖的表称为父表。 o 支持事务回滚以及系统崩溃的修复能力并且支持多版本并发控制的事务安全。 o 支持mvcc多版本并发控制的行级锁就是通过多版本控制来实现的乐观锁 o 索引使用的是BTree 优缺点InnoDB的优势在于提供了良好的事务处理、崩溃修复能力和并发控制。缺点是读写效率较差占用的数据空间相对较大。 • MyISAM 存储引擎 不支持事务、支持表级锁 支持全文搜索 缓冲池只缓存索引文件不缓存数据文件 MyISAM 存储引擎表由数据文件MYD和索引文件 MYI组成 我们项目中常用到的是innoDBInnoDB存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全但是对比Myisam的存储引擎InnoDB写的处理效率差一些并且会占用更多的磁盘空间以保留数据和索引。
数据库的隔离级别
读未提交读已提交可重复读串行化四个 默认是可重复读我们在项目中一般用读已提交(Read Commited)这个隔离级别
mysql的优化
1sql语句添加索引 2将数据库的数据预热到redis中 3 主从复制读写分离 4分库分表 5分页查询
分库分表
垂直拆分是将表按列拆分成多个表且每个表中要包含主键尽量把长度较短访问频率较高的属性放在主表里。 水平拆分是将一个表通过 取模、按照日期范围 等等拆分成若干个表。 垂直分库如果没有按照合理的业务逻辑去拆分后期会带来跨库join分布式事务等 跨库join会导致查询性能低下分布式事务下会导致因数据不一致造成很多脏数据的存在。 怎么去 分的
搭建mycat的核心配置文件
schema.xml配置逻辑库表分片和读写分离 rule.xml具体的分片规则和分片算法 server.xml配置默认的数据库和用户表权限
主从复制读写分离.
主从复制是用来建立一个和主数据库完全一样的数据库环境称为从数据库
读写分离就是在主服务器上修改数据会同步到从服务器从服务器只能提供读取数据不能写入实现备份的同时也实现了数据库性能的优化以及提升了服务器安全。 主从原理 数据库有个bin-log二进制文件记录了所有的sql语句。
只需要把主数据库的bin-log文件中的sql语句复制。
让其从数据的relay-log重做日志文件中在执行一次这些sql语句即可。
主从实现方式
同步复制所谓的同步复制意思是master的变化必须等待slave-1,slave-2,…,slave-n完成后才能返回。 异步复制如同AJAX请求一样。master只需要完成自己的数据库操作即可。至于slaves是否收到二进制日志是否完成操作不用关心。MYSQL的默认设置。 半同步复制master只保证slaves中的一个操作成功就返回其他slave不管。
读写分离的实现方式
1基于程序代码内部实现 在代码中根据 select 、insert 进行路由分类这类方法也是目前生产环境下应用最广泛的。优点是性能较好因为程序在代码中实现不需要增加额外的硬件开支缺点是需要开发人员来实现运维人员无从下手。 2 基于中间代理层实现 代理一般介于应用服务器和数据库服务器之间代理数据库服务器接收到应用服务器的请求后根据判断后转发到。
索引
分类 按照逻辑分类索引可分为 主键索引一张表只能有一个主键索引不允许重复不允许为null 唯一索引数据列不允许重复允许为NULL值一张表可有多个唯一索引但是一个唯一索引只能包含 一列比如身份证号码卡号都可以作为唯一索引 普通索引一张表可以创建多个普通索引一个普通索引可以包含多个字段允许数据重复允许NULL值插入 全文索引让搜索关键词更高效的一种索引 按照物理分类索引可分为 聚集索引一般是表中的主键索引如果表中没有显示指定主键则会选择表中的第一个不允许为NULL的唯一索引如果还是没有就采用Innodb存储引擎为每行数据内置的6字节rowid作为聚集索引。每张表只有一个聚集索引因为聚集索引的兼职的逻辑顺序决定了表中相应行的物理顺序。聚集索引在精确查找和范围查找方面有良好的性能表现相对于普通索引和全表扫描聚集索引就显得弥足珍贵聚集索引选择还是要慎重一般不会让没有语义的自增id充当聚集索引 非聚集索引该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同非主键的那一列一个表中可以拥有多个非聚集索引
放弃索引优化
1对查询进行优化应尽量避免全表扫描首先应考虑在 where 及 order by 涉及的列上建立索引。 2 应尽量避免在 where 子句中使用!或操作符 3应尽量避免在 where 子句中对字段进行 null值判断。如 select id from t where num is null 可以在 num 上设置默认值 0确保表中 num 列没有 null 值然后这样查询:selectid from t where num0 4 应尽量避免在 where 子句中使用 or 来连接条件 如select id from t where num10 or num20 可以使用可以这样查询 select id from t where num10 union all select id from t where num20 5以%开头的模糊查询也会导致全表扫描 select id from t where name like ‘%abc%’如果要提高效率的话可以考虑全文检索来解决。 6in 和 not in 如 select id from t where num in(1,2,3) 对于连续的数值能用 between 就不要用 in 了 select id from t where num between 1 and 3 7应尽量避免在 where 子句中对字段进行表达式操作 如selectid from t where num/2100应改为: select id from t where num1002* 8,应尽量避免在 where 子句中对字段进行函数操作 以上将导致引擎放弃使用索引而 进行全表扫描。
数据库为什么使用B树而不是B树
1B树只适合随机检索而B树同时支持随机检索和顺序检索比较符合实际需求 2B树空间利用率更高由于内部节点只存键文件小且数据命中的概率高可减少I/O次数磁盘读写代价更低 3B树的查询效率更加稳定。随机查询时都必须走一条从根节点到叶节点的路查询效率略低而B树查询靠近根节点的数据时效率会更高 4数据库中基于范围的查询是非常频繁的B树的叶子节点使用指针顺序连接在一起只要遍历叶子节点就可以实现整棵树的遍历而B树不支持这样的操作 5B树的叶子节点包含所有关键字并以有序的链表结构存储,增删快
索引设计的原则
1.where子句中查询条件对应的列去添加索引 2.基数较小的类索引效果较差没有必要在此列建立索引 3.尽量使用短索引如果对长字符串列进行索引应该指定一个前缀长度*检索字段的前面的若干个字符*这样能够节省大量索引空间 4.不要过度添加索引。索引需要额外的磁盘空间降低操作的性能。因为在修改表内容的时候索引会进行更新甚至重构索引列越多这个时间就会越长。所以只保持需要的索引有利于查询即可。 5.数据量小的表最好也不使用索引因为数据量较少的话可能查询全部数据比查询索引还要快索引就可能不会产生优化的效果了 6.text、image和bit的数据类型的列不要建立索引 7.定义有外键的数据列一定要建立索引。 8.尽量的扩展索引不要新建索引。比如表中已经有a的索引现在要加(a,b)的索引那么只需要修改原来的索引即可。
事务的隔离级别
● 读未提交允许另外一个事务可以看到这个事务未提交的数据最低级别任何情况都无法保证。 ● 读已提交保证一个事务修改的数据提交后才能被另一事务读取而且能看到该事务对已有记录的更新可避免脏读的发生。 ● 可重复读保证一个事务修改的数据提交后才能被另一事务读取但是不能看到该事务对已有记录的更新可避免脏读、不可重复读的发生。 ● 串行化一个事务在执行的过程中完全看不到其他事务对数据库所做的更新可避免脏读、不可重复读、幻读的发生。
mysql的锁有哪些
按照锁的粒度
行级锁给表的每一行加锁开销大加锁慢会出现死锁粒度小冲突概率低并发度高
表级锁给表加锁开销小加锁快不会出现死锁粒度大冲突概率高并发度低。
页级锁开销和加锁时间、锁定粒度界于表锁和行锁之间会出现死锁并发度一般 锁的类别上分 共享锁读锁就是读的时候加共享锁可以加多个在读的时候不能写操作 排他锁写锁只能加一个就是写的时候不能受其他事务的干扰 什么是死锁怎么解决 死锁是指多个事务在同一资源上相互占用并请求锁定对方的资源从而导致恶性循环的现象。 常见的解决死锁的方法 1、如果不同程序会并发存取多个表尽量约定以相同的顺序访问表可以大大降低死锁机会。 2、在同一个事务中尽可能做到一次锁定所需要的所有资源减少死锁产生概率 3、对于非常容易产生死锁的业务部分可以尝试使用升级锁定颗粒度通过表级锁定来减少死锁产生的 概率 什么是乐观锁和悲观锁?
1、乐观锁的话就是比较乐观每次去拿数据的时候认为别人不会修改所以不会上锁但是在更新的时候会判断一下在此期间别人有没有去更新这个数据可以使用版本号机制或者CAS 算法实现。乐观锁在读操作比较多的场景比较适用这样可以提高吞吐量就像数据库提供的write_condition机制其实都是乐观锁 2、悲观锁的话就是每次去拿数据的时候也认为别人会修改数据这个时候就会加上锁这就导致其他线程想拿数据的话就会阻塞直到这个线程修改完成才会释放锁让其他线程获取数据。在数据库里的行级锁、表级锁都是在操作之前就先锁住数据再操作数据 都属于悲观锁。Java中的 synchronized和 ReentrantLock 等独占锁就是悲观锁思想的实现。
主键索引和唯一索引有啥区别
键是一种约束唯一索引是一种索引两者在本质上是不同的。 主键创建后一定包含一个唯一索引唯一索引并不一定就是主键。 主键列在创建时已经默认为空值 唯一索引了。 主键可以被其他表引用为外键而唯一索引不能。 主键更适合那些不容易更改的唯一标识如自动递增列、身份证号等。 一个表最多只能创建一个主键但可以创建多个唯一索引 在 RBO 模式下主键的执行优先级要高于唯一索引。两者可以提高查询的速度 唯一索引列允许空值而主键列不允许为空值。
Redis
Redis缓存预热
缓存预热就是系统上线后提前将相关的缓存数据直接加载到缓存系统。 避免在用户请求的时候先查询数据库然后再将数据缓存的问题 用户直接查询事先被预热的缓存数据 缓存预热解决方案 1直接写个缓存刷新页面上线时手工操作下。 2数据量不大可以在项目启动的时候自动进行加载。
Redis 是单线程的么线程安全么?
redis 是单线程,线程安全。 因为 Redis 是基于内存的操作CPU 不是 Redis 的瓶颈Redis 的瓶颈最有可能是机器内存的大小或者网络宽带。 redis 实际上是采用了线程封闭的观念把任务封闭在一个线程自然避免了线程安全问题。 不过对于需要依赖多个 redis 操作的复合操作来说依然需要锁而且有可能是分布式锁。
redis传送门
MQ
MQ消息中间件的作用为什么要用消息中间件
1、异步处理、有些业务不需要立即执行的就可以把消息放入队列然后在处理这样可以不影响主线程运行 2、应用解耦 降低模块之间的耦合度提升项目的扩展性。 3、流量削峰 应用可能会因为流量过大导致挂掉所以一般这类前端请求都会加入消息队列。在秒杀场景中经常见到.
如何保证MQ消息不丢失如何解决数据丢失的问题
1、持久化设置、 设置交换机持久化、队列持久化、 消息持久化 2、ACK确认机制、是消费端消费完成要通知服务端服务端才把消息从内存删除。 3、设置集群镜像模式 4、消息补偿机制、根据状态字段进行补偿发送完成和接收完成都要对状态做出变更定时任务检测超时没有接收的或者接收失败的重新发送。
如何确保消息正确的发送到MQ?
1、rabbitmq中提供了事物和confirm(肯否儿)的机制事物就类似于数据库的事物开启执行提交如果过程中发生任何异常就会触发回滚机制我们可以在回滚中加入一些逻辑处理重新发送或者日志记录 2、配置生产者确认的机制就是在消息发送之后该消息会被指定唯一的ID如果有消息成功被交换机转发到队列之后mq会给生产者发送ack确认如果没有队列接收消息那么会发送错误回执消息给生产者生产者可以尝试重试发送或者日志记录.
如何避免消息重复投递或重复消费
1、在消息生产时MQ 内部针对每条生产者发送的消息生成一个 消息id作为去重的依据避免重复的消息进入队列 2、在消息消费时要求消息体中必须要有一个业务id作为去重的依据避免同一条消息被重复消费。
使用MQ的优点和缺点是什么
优点 解耦、异步、削峰 缺点 1、需要保证高可用、MQ若是挂了容易引起整个服务挂掉 2、系统复杂性增加、需要保证让消息可靠的传递、消息正确的被消费等问题
使用MQ的场景能举例说一些么
调用短信通知、邮件通知.
activeMQ和rabbitMQ有什么区别
ActiveMQ基于jms协议java开发强在MQ领域所有想要的功能基本都有开箱即用。 rabbitMQ基于AMQP协议开发的使用erlang语言开发重在基于内存性能很高。
RabbitMQ 宕机了怎么处理
RabbitMQ 提供了持久化的机制将内存中的消息持久化到硬盘上即使重启 RabbitMQ消息也不会丢失。持久化队列和非持久化队列的区别是持久化队列会被保存在磁盘中固定并持久的存储当 Rabbit 服务重启后该队列会保持原来的状态在RabbitMQ 中被管理而非持久化队列不会被保存在磁盘中Rabbit 服务重启后队列就会消失。非持久化比持久化的优势就是由于非持久化不需要保存在磁盘中所以使用速度就比持久化队列快。即是非持久化的性能要高于持久化。而持久化的优点就是消息会一直存在不会随服务的重启或服务器的宕机而消失。使用的时候需要根据实际需求来判断具体如何使用。
Spring
Springmvc 的运行原理
1.客户端请求提交到DispatcherServlet前端控制器 2.由DispatcherServlet控制器查询一个或多个HandlerMapping处理器映射器找到处理请求的Controller 3.DispatcherServlet将请求提交到Controller也称为Handler 4.Controller调用业务逻辑处理后返回ModelAndView(模型视图数据) 5.DispatcherServlet查询一个或多个ViewResoler视图解析器找到ModelAndView指定的视图 视图负责将结果显示到客户端
Spring中的设计模式有哪些
工厂模式BeanFactory 就是简单工厂模式的体现用来创建对象的实例 单例模式Bean 默认为单例模式。 模板方法用来解决代码重复的问题。 代理模式Spring 的 AOP 功能用到了 JDK 的动态代理和 CGLIB 字节码生成术 观察者模式定义对象键一种一对多的依赖关系当一个对象的状态发生改变时所有依赖于它的对象都会得到通知被制动更新.
简单介绍一下Spring bean 的生命周期
就是从创建到销毁的过程通过构造方法或者工厂方法实例化bean对象并通过依赖注入设置对象的属性。将Bean实例传递给Bean的前置处理器调用Bean的初始化方法再将Bean实例传递给Bean的后置处理器的然后使用Bean。容器关闭之前调用Bean的销毁方法销毁实例
spring有哪些核心组件
Spring Core(核心)核心类库提供 IOC 服务 Spring Context 提供了框架式的bean的访问方式以及企业级功能如JNDI定时任务等。 Spring AOPAOP 服务 Spring ORM: 对现有ORM框架的支持。 Spring DAO对 JDBC 的抽象简化了数据访问异常的处理 Spring Web提供了基本的面向 Web 的特性 例如多方文件上传 Spring MVC提供面向 Web 应用的 Model-View-Controller 实现。
#{}和${}的区别是什么
#{}是占位符KaTeX parse error: Expected EOF, got # at position 19: …连接符。 Mybatis在处理#̲{}时会将sql中的#{}替…{}时就是把${}替换成变量的值。 使用#{}可以有效的防止SQL注入提高系统安全性.
IOC/DI 的区别
控制反转把对象创建和对象之间的调用过程交给Spring进行管理传统应用程序都是由我们在类内部主动创建依赖对象从而导致类与类之间高耦合有了IoC容器后把创建和查找依赖对象的控制权交给了容器由容器进行注入组合对象所以对象与对象之间是松散耦合使得程序的整个体系结构变得非常灵活。 IoC的一个重点是在系统运行中动态的向某个对象提供它所需要的其他对象。这一点是通过DI来实现的。比如对象A需要操作数据库以前我们总是要在A中自己编写代码来获得一个Connection对象有了 spring我们就只需要告诉springA中需要一个Connection至于这个Connection怎么构造何时构造A不需要知道。在系统运行时spring会在适当的时候制造一个Connection注入到ioc中这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行而这个Connection是由spring注入到A中的。依赖注入的底层是通过反射来实现的它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性spring就是通过反射来实现注入的。
分布式ID生成解决方案
● UUID 优点 简单代码方便性能好全球唯一 缺点 没有排序无法保证趋势递增。 UUID是36位字符串查询的效率比较低存储空间比较大 ● Redis生成ID 优点 不依赖于数据库灵活方便且性能优于数据库。 数字ID天然排序对分页或者需要排序的结果很有帮助。 缺点 如果系统中没有Redis还需要引入Redis增加系统复杂度。 需要编码和配置的工作量比较大。 ● 雪花算法snowflake snowflake是Twitter开源的分布式ID生成算法结果是一个long型的ID。 其核心思想是使用41bit作为毫秒数10bit作为机器的ID12bit作为毫秒内的流水号最后还有一个符号位永远是0性能极好使用简单。
ES
为什么要使用Elasticsearch?
1、横向可扩展性好、只需要增加服务器简单配置启动进程就可以并入集群 2、提供更好的分布式特性、同一个索引分成多个分片sharding分而治提升处理效率 3、扩展性很强各种规模的公司都可以选用根据自己的数据规模选择集群的大小并且有合理的分布式架构单个计算节点宕机不会造成整体系统的崩溃 4、可以根据不同的需求方便地定制各类查询使用简单或者高级的ranking策略
ES的应用场景
结合项目进行解答
微服务
Spring是一个生态体系
Spring Framework是整个spring生态的**基石针对于开发的WEB层(springMVC)、业务层(IoC)、持久层(jdbcTemplate)等都提供了多种配置解决方案 Spring Boot默认集成了很多第三方包将过去繁杂的配置改为注解和Java代码实现 Spring Cloud是一整套基于Spring Boot的微服务解决方案包括配置管理、注册中心、负载均衡、限流、网关等。
Spring的常用注解
bean,controller,restcontroller,requestbody,responsebody,service,autowire,recourse,requestmapping(get,post,put),requestparam,paramComponentcomponentscan,value,configuration,Transactional
Springboot注解
springbootapplication,configurationproperties,EnableAutoConfiguration,autoconfiguration,enablediscoveryclient,enablefeignclients,feignclient,SpringBootConfiguration
Springboot自动装配
Springboot项目在启动的时候因为我们在启动类上添加了springbootapplication注解这个注解内部封装了三个核心注解第一个是springbootconfiguration他申明了boot项目在启动的时候自动装配的功能第二个是enableautoconfiguration他内部封装了boot项目启动时的自动装配内容底层通过java的反射调用meta-info中的spring-factories文件中的具体配置信息在项目启动时就将部分内容注入到spring ioc容器中当然一些不常用的他只是做了内部配置需要使用的时候自己通过注解调用就行第三个注解是componentscan这个注解通过映射内部的配置路劲去自动扫描个别需要手动配置的路劲在项目启动时开发者额外申明即可。 另外main方法中调用了springapplication的run方法调用时将当前类的class传给了boot底层因为考虑多进程问题将传入的class封装到了一个数组当中然后底层有一个类叫stopwatch确定我们当前传如的springapplication没有启动的情况下调用start方法启动该boot项目启动方法中对启动项目的标识名称和启动时间做了记录。
Nacos
因为我们最近这个项目使用的时bootcloud注册中心这块使用的是nanos就类似于dubbo框架里边咱们一般用的zk主要实现微服务架构下各模块的相互访问另外也用到了他配置中心的功能因为咱们项目启动的时候会读取配置信息而很多配置的话是动态的比如环境切换正常来讲当我们修改配置后需要重启服务对于正式环境来讲重新打包重启服务器的代价是相当高的所以通过配置中心我们可以再客户端修改对应配置后将新的配置自动同步到已部署好的代码当中避免了重新部署、重启等问题通过是通过refreshscope注解实现的底层使用代理模式使用反射动态更新 p r e f i x − {prefix}-prefix−{spring.profiles.active}.${file-extension} serverId-dev.yaml 支持配置信息的持久化支持集群。
Ribbon负载均衡
之前项目上负载均衡这块儿用过ribbonribbon负载均衡的策略总共有七种之前我们主要通过三种策略来实现轮询、随机、权重默认使用的是轮询。 轮询底层每次记录当前服务的位置当有新的任务分配的时候以当前位置加一作为即将接受任务的角标然后根据该角标从集群服务的列表中拿到对应的服务然后将这个任务分配给该服务。 随机其实就是拿到一个不超过集群数量的随机值然后使用该随机值作为下标去集群服务的列表中获取对应的服务然后将当前任务交给他执行这种算法策略在少量请求时不能做到均衡分配但如果请求量大的时候每台集群的服务器接受的任务趋于均衡 权重策略在初始化的时候会启动一个定时任务每隔30S重新计算一次具体的计算方式就是通过集群服务器的平均响应时间减去当前服务器的响应时间作为分配给当前服务器的权重比例当前服务器压力越大响应越慢响应时间越长算出来的结果越小权重越低。 Feign的工作原理 启动类添加EnableFeignClients注解Spring会扫描标记了FeignClient注解的接口并生成此接口的代理对象, FeignClient内部指定了被调用服务的标识将接口注入到Spring IOC容器中Feign会从注册中心获取到服务标识当消费者访问时会根据请求路劲识别注册中心服务对应的接口。 网络调用的时候通过代理模式为每个接口方法创建一个RequestTemplate而requsttemplate内部封装了httpurlconnection,httpclient,okhttp等五种请求方式调用时可以根据yml配置指定对应的请求方式。 Spring Cloud项目中用到哪些组件
Nacos:注册中心配置中心 Ribbon:负载均衡 Feign远程调用 Sentinel限流熔断降级服务容错 Gateway网关路由过滤限流
Feign的工作原理?
启动类添加EnableFeignClients注解Spring会扫描标记了FeignClient注解的接口并生成此接口的代理对象, FeignClient内部指定了被调用服务的标识标将接口注入到Spring IOC容器中Feign会从注册中心获取到服务标识当消费者访问时会根据请求路劲识别注册中心服务对应的接口。 网络调用的时候通过代理模式为每个接口方法创建一个RequestTemplate而requsttemplate内部封装了httpurlconnection,httpclient,okhttp等五种请求方式调用时可以根据yml配置指定对应的请求方式。 Gateway的作用 路由请求时所有请求先回通过网关的配置路劲访问到网关然后网关经过校验将任务分配给具体的服务。 过滤每次网络请求执行到网关的时候一般过滤request对象携带的参数、头信息、cookie根据前后端的校验规则来确认是否是本应用客户端发起的请求从而决定是否放行。 限流gateway有限流的功能但我们公司限流用的是sentinelgateway的限流主要通过令牌桶算法来实现说白了就是在一个容器内我们设定了一个定时写入令牌的规则当请求发起时必须携带一个令牌后台校验令牌通过才可以访问如果没有令牌或者是无效的令牌就拒绝访问因为容器设置了最大令牌的限量如果桶满新生成的令牌会被丢弃这样如果同一时间大量请求来临只有少部分请求能获取到令牌让其余没有令牌的请求原路返回以此实现限流的功能。
服务部署
说下Linux常用命令
cd进入某个目录 pwd查看当前目录 ls查看当前目录下有哪些文件 mkdir创建一个目录 cp复制文件 mv 文件移动 rm -rf递归强制删除 tar -xzvf解压缩 tail -200f 文件名动态输出日志最后200行 kill -9 进程pid强制杀死进程 ps -ef|grep tomcat查看tomcat进程pid
持续更新… 今天的分享就到这里啦若本文对你有所帮助请点赞收藏就是对我最大的支持。