机关网站建设方案,英文网站字体大小,全光网络架构图,无锡华庄行业网站建设面试题整理
一、Java基础
1、Java 语言有哪些特点 简单易学#xff1b; 面向对象#xff08;封装#xff0c;继承#xff0c;多态#xff09;#xff1b; 平台无关性#xff08; Java 虚拟机实现平台无关性#xff09;#xff1b; 支持多线程#xff08; C 语言…面试题整理
一、Java基础
1、Java 语言有哪些特点 简单易学 面向对象封装继承多态 平台无关性 Java 虚拟机实现平台无关性 支持多线程 C 语言没有内置的多线程机制因此必须调用操作系统的多线程功能来进行多线程程序设计而 Java 语言却提供了多线程支持 可靠性 安全性 支持网络编程并且很方便 Java 语言诞生本身就是为简化网络编程设计的因此 Java 语言不仅支持网络编程而且很方便 编译与解释并存
2、JVM、JRE和JDK的关系
JVM Java Virtual Machine是Java虚拟机Java程序需要运行在虚拟机上不同的平台有自己的虚拟机因此Java语言可以实现跨平台。
JRE Java Runtime Environment包括Java虚拟机和Java程序所需的核心类库等。核心类库主要是java.lang包包含了运行Java程序必不可少的系统类如基本数据类型、基本数学函数、字符串处理、线程、异常处理类等系统缺省加载这个包
如果想要运行一个开发好的Java程序计算机中只需要安装JRE即可。
JDK Java Development Kit是提供给Java开发人员使用的其中包含了Java的开发工具也包括了JRE。所以安装了JDK就无需再单独安装JRE了。其中的开发工具编译工具(javac.exe)打包工具(jar.exe)等 3、字符型常量和字符串常量的区别?
形式 : 字符常量是单引号引起的一个字符字符串常量是双引号引起的 0 个或若干个字符含义 : 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置)占内存大小 字符常量只占 2 个字节; 字符串常量占若干个字节 (注意 char 在 Java 中占两个字节),
4、注释有哪几种
Java 中的注释有三种
单行注释多行注释文档注释。
5、标识符和关键字的区别
在我们编写程序的时候需要大量地为程序、类、变量、方法等取名字于是就有了标识符简单来说标识符就是一个名字。但是有一些标识符Java 语言已经赋予了其特殊的含义只能用于特定的地方这种特殊的标识符就是关键字。因此关键字是被赋予特殊含义的标识符。比如在我们的日常生活中 “警察局”这个名字已经被赋予了特殊的含义所以如果你开一家店店的名字不能叫“警察局”“警察局”就是我们日常生活中的关键字。
Java 中常见的关键字
分类关键字访问控制privateprotectedpublic类方法和变量修饰符abstractclassextendsfinalimplementsinterfacenativenewstaticstrictfpsynchronizedtransientvolatile程序控制breakcontinuereturndowhileifelseforinstanceofswitchcasedefault错误处理trycatchthrowthrowsfinally包相关importpackage基本类型booleanbytechardoublefloatintlongshortnulltruefalse变量引用superthisvoid保留字gotoconst
Final
(1) 类不能被继承
(2) 子类中方法不能被重写JVM会尝试将其关联。
(3) 变量为常量编译阶段存储在常量池中。
Static
(1) 修饰的类可以直接通过类来调用而不需要new
(2) 修饰的方法块JVM会有限加载。
(3) 修饰的变量分配在内存堆上引用时指向同一个地质而不会重新分配内存空间。
6、自增自减运算符
在写代码的过程中常见的一种情况是需要某个整数类型变量增加 1 或减少 1Java 提供了一种特殊的运算符用于这种表达式叫做自增运算符)和自减运算符–。 和 – 运算符可以放在变量之前也可以放在变量之后当运算符放在变量之前时(前缀)先自增/减再赋值当运算符放在变量之后时(后缀)先赋值再自增/减。例如当 b a 时先自增自己增加 1再赋值赋值给 b当 b a 时先赋值(赋值给 b)再自增自己增加 1。也就是a 输出的是 a1 的值a输出的是 a 值。用一句口诀就是“符号在前就先加/减符号在后就后加/减”。
7、continue、break 和 return 的区别
在循环结构中当循环条件不满足或者循环次数达到要求时循环会正常结束。但是有时候可能需要在循环的过程中当发生了某种条件之后 提前终止循环这就需要用到下面几个关键词
continue 指跳出当前的这一次循环继续下一次循环。break 指跳出整个循环体继续执行循环下面的语句。
return 用于跳出所在方法结束该方法的运行。return 一般有两种用法
return; 直接使用 return 结束方法执行用于没有返回值函数的方法return value; return 一个特定值用于有返回值函数的方法
8、静态方法为什么不能调用非静态成员?
这个需要结合 JVM 的相关知识主要原因如下 静态方法是属于类的在类加载的时候就会分配内存可以通过类名直接访问。而非静态成员属于实例对象只有在对象实例化之后才存在需要通过类的实例对象去访问。 在类的非静态成员不存在的时候静态成员就已经存在了此时调用在内存中还不存在的非静态成员属于非法操作。
9、静态方法和实例方法有何不同
1、调用方式
在外部调用静态方法时可以使用 类名.方法名 的方式也可以使用 对象.方法名 的方式而实例方法只有后面这种方式。也就是说调用静态方法可以无需创建对象 。
不过需要注意的是一般不建议使用 对象.方法名 的方式来调用静态方法。这种方式非常容易造成混淆静态方法不属于类的某个对象而是属于这个类。
因此一般建议使用 类名.方法名 的方式来调用静态方法。
2、访问类成员是否存在限制
静态方法在访问本类的成员时只允许访问静态成员即静态成员变量和静态方法不允许访问实例成员即实例成员变量和实例方法而实例方法不存在这个限制。
10、重载和重写的区别
重载就是同样的一个方法能够根据输入数据的不同做出不同的处理
重写就是当子类继承自父类的相同方法输入数据一样但要做出有别于父类的响应时你就要覆盖父类方法
11、 和 equals() 的区别 对于基本类型和引用类型的作用效果是不同的
对于基本数据类型来说 比较的是值。对于引用数据类型来说 比较的是对象的内存地址。 因为 Java 只有值传递所以对于 来说不管是比较基本数据类型还是引用数据类型的变量其本质比较的都是值只是引用类型变量存的值是对象的地址。 equals() 不能用于判断基本数据类型的变量只能用来判断两个对象是否相等。equals()方法存在于Object类中而Object类是所有类的直接或间接父类。
12、hashCode() 与 equals()
hashCode() 的作用是获取哈希码int 整数也称为散列码。这个哈希码的作用是确定该对象在哈希表中的索引位置。
hashCode()定义在 JDK 的 Object 类中这就意味着 Java 中的任何类都包含有 hashCode() 函数。另外需要注意的是 Object 的 hashCode() 方法是本地方法也就是用 C 语言或 C 实现的该方法通常用来将对象的内存地址转换为整数之后返回。
散列表存储的是键值对(key-value)它的特点是能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码可以快速找到所需要的对象
那为什么两个对象有相同的 hashCode 值它们也不一定是相等的 如果两个对象的hashCode 值相等那这两个对象不一定相等哈希碰撞。 如果两个对象的hashCode 值相等并且equals()方法返回 true我们才认为这两个对象相等。 如果两个对象的hashCode 值不相等我们就可以直接认为这两个对象不相等。
13、为什么重写 equals() 时必须重写 hashCode() 方法
因为两个相等的对象的 hashCode 值必须是相等。也就是说如果 equals 方法判断两个对象是相等的那这两个对象的 hashCode 值也要相等。
如果重写 equals() 时没有重写 hashCode() 方法的话就可能会导致 equals 方法判断是相等的两个对象hashCode 值却不相等。
思考 重写 equals() 时没有重写 hashCode() 方法的话使用 HashMap 可能会出现什么问题。
总结 equals 方法判断两个对象是相等的那这两个对象的 hashCode 值也要相等。 两个对象有相同的 hashCode 值他们也不一定是相等的哈希碰撞。 java规定
如果两个对象的hashCode()相等那么他们的equals()不一定相等。
如果两个对象的equals()相等那么他们的hashCode()必定相等。14、基本数据类型
Java 中有 8 种基本数据类型分别为
6 种数字类型 byte、short、int、long、float、double1 种字符类型char1 种布尔型boolean。
这 8 种基本数据类型的默认值以及所占空间的大小如下
基本类型位数字节默认值int3240short1620long6480Lbyte810char162‘u0000’float3240fdouble6480dboolean1false
另外对于 boolean官方文档未明确定义它依赖于 JVM 厂商的具体实现。逻辑上理解是占用 1 位但是实际中会考虑计算机高效存储因素。
注意
Java 里使用 long 类型的数据一定要在数值后面加上 L否则将作为整型解析。char a hchar :单引号String a hello :双引号。
这八种基本类型都有对应的包装类分别为Byte、Short、Integer、Long、Float、Double、Character、Boolean 。
包装类型不赋值就是 Null 而基本类型有默认值且不是 Null。
另外这个问题建议还可以先从 JVM 层面来分析。
基本数据类型直接存放在 Java 虚拟机栈中的局部变量表中而包装类型属于对象类型我们知道对象实例都存在于堆中。相比于对象类型 基本数据类型占用的空间非常小。
15、包装类型的常量池技术
Java 基本类型的包装类的大部分都实现了常量池技术。
Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128127] 的相应类型的缓存数据Character 创建了数值在 [0,127] 范围的缓存数据Boolean 直接返回 True or False。
所有整型包装类对象之间值的比较全部使用 equals 方法比较。
16、内部类
什么是内部类
在Java中可以将一个类的定义放在另外一个类的定义内部这就是内部类。内部类本身就是类的一个属性与其他属性定义方式一致。
内部类的分类
内部类可以分为四种成员内部类、局部内部类、匿名内部类和静态内部类。
静态内部类
定义在类内部的静态类就是静态内部类。
成员内部类
定义在类内部成员位置上的非静态类就是成员内部类。
局部内部类
定义在方法中的内部类就是局部内部类。
匿名内部类
匿名内部类就是没有名字的内部类日常开发中使用的比较多。
除了没有名字匿名内部类还有以下特点
匿名内部类必须继承一个抽象类或者实现一个接口。匿名内部类不能定义任何静态成员和静态方法。当所在的方法的形参需要被匿名内部类使用时必须声明为 final。匿名内部类不能是抽象的它必须要实现继承的类或者实现的接口的所有抽象方法。
内部类的优点
我们为什么要使用内部类呢因为它有以下优点
一个内部类对象可以访问创建它的外部类对象的内容包括私有数据内部类不为同一包的其他类所见具有很好的封装性内部类有效实现了“多重继承”优化 java 单继承的缺陷。匿名内部类可以很方便的定义回调。
为什么局部内部类和厦名内部类只能访问局部final变量 因为局部内部类和匿名内部类是在方法体内部定义的而局部变量是在方法体内部定义的而且局部变量的生命周期只在方法体内部当方法体执行完毕后局部变量就会被销毁而局部内部类和匿名内部类可能会在方法体外部使用所以为了保证局部内部类和匿名内部类可以正常使用只能访问局部final变量因为final变量的生命周期比局部变量更长所以可以保证局部内部类和匿名内部类可以正常使用。 17、成员变量与局部变量的区别有哪些 语法形式 从语法形式上看成员变量是属于类的而局部变量是在代码块或方法中定义的变量或是方法的参数成员变量可以被 public,private,static 等修饰符所修饰而局部变量不能被访问控制修饰符及 static 所修饰但是成员变量和局部变量都能被 final 所修饰。 存储方式 从变量在内存中的存储方式来看,如果成员变量是使用 static 修饰的那么这个成员变量是属于类的如果没有使用 static 修饰这个成员变量是属于实例的。而对象存在于堆内存局部变量则存在于栈内存。 生存时间 从变量在内存中的生存时间上看成员变量是对象的一部分它随着对象的创建而存在而局部变量随着方法的调用而自动消失。 默认值 从变量是否有默认值来看成员变量如果没有被赋初则会自动以类型的默认值而赋值一种情况例外:被 final 修饰的成员变量也必须显式地赋值而局部变量则不会自动赋值。
18、创建一个对象用什么运算符?对象实体与对象引用有何不同?
new 运算符new 创建对象实例对象实例在堆内存中对象引用指向对象实例对象引用存放在栈内存中。
一个对象引用可以指向 0 个或 1 个对象一根绳子可以不系气球也可以系一个气球;一个对象可以有 n 个引用指向它可以用 n 条绳子系住一个气球。
19、对象的相等与指向他们的引用相等,两者有什么不同? 对象的相等一般比较的是内存中存放的内容是否相等。 引用相等一般比较的是他们指向的内存地址是否相等。
20、一个类的构造方法的作用是什么? 若一个类没有声明构造方法该程序能正确执行吗?
构造方法主要作用是完成对类对象的初始化工作。
如果一个类没有声明构造方法也可以执行因为一个类即使没有声明构造方法也会有默认的不带参数的构造方法。如果我们自己添加了类的构造方法无论是否有参Java 就不会再添加默认的无参数的构造方法了这时候就不能直接 new 一个对象而不传递参数了所以我们一直在不知不觉地使用构造方法这也是为什么我们在创建对象的时候后面要加一个括号因为要调用无参的构造方法。如果我们重载了有参的构造方法记得都要把无参的构造方法也写出来无论是否用到因为这可以帮助我们在创建对象的时候少踩坑。
21、构造方法有哪些特点是否可被 override?
构造方法特点如下
名字与类名相同。没有返回值但不能用 void 声明构造函数。生成类的对象时自动执行无需调用。
构造方法不能被 override重写,但是可以 overload重载,所以你可以看到一个类中有多个构造函数的情况。
22、面向对象三大特征
封装
封装是指把一个对象的状态信息也就是属性隐藏在对象内部不允许外部对象直接访问对象的内部信息。但是可以提供一些可以被外界访问的方法来操作属性。就好像我们看不到挂在墙上的空调的内部的零件信息也就是属性但是可以通过遥控器方法来控制空调。如果属性不想被外界访问我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法那么这个类也没有什么意义了。就好像如果没有空调遥控器那么我们就无法操控空凋制冷空调本身就没有意义了当然现在还有很多其他方法 这里只是为了举例子。
继承
不同类型的对象相互之间经常有一定数量的共同点。例如小明同学、小红同学、小李同学都共享学生的特性班级、学号等。同时每一个对象还定义了额外的特性使得他们与众不同。例如小明的数学比较好小红的性格惹人喜爱小李的力气比较大。继承是使用已存在的类的定义作为基础建立新类的技术新类的定义可以增加新的数据或新的功能也可以用父类的功能但不能选择性地继承父类。通过使用继承可以快速地创建新的类可以提高代码的重用程序的可维护性节省大量创建新类的时间 提高我们的开发效率。
关于继承如下 3 点请记住
子类拥有父类对象所有的属性和方法包括私有属性和私有方法但是父类中的私有属性和方法子类是无法访问只是拥有。子类可以拥有自己属性和方法即子类可以对父类进行扩展。子类可以用自己的方式实现父类的方法。以后介绍。
多态
多态顾名思义表示一个对象具有多种的状态具体表现为父类的引用指向子类的实例。
多态的特点:
对象类型和引用类型之间具有继承类/实现接口的关系引用类型变量发出的方法调用的到底是哪个类中的方法必须在程序运行期间才能确定多态不能调用“只在子类存在但在父类不存在”的方法如果子类重写了父类的方法真正执行的是子类覆盖的方法如果子类没有覆盖父类的方法执行的是父类的方法。
面向对象五大基本原则是什么
单一职责原则SRP(Single Responsibility Principle) 类的功能要单一不能包罗万象跟杂货铺似的。开放封闭原则OCP(OpenClose Principle) 一个模块对于拓展是开放的对于修改是封闭的想要增加功能热烈欢迎想要修改哼一万个不乐意。里式替换原则LSP(the Liskov Substitution Principle LSP) 子类可以替换父类出现在父类能够出现的任何地方。比如你能代表你爸去你姥姥家干活。哈哈~~依赖倒置原则DIP(the Dependency Inversion Principle DIP) 高层次的模块不应该依赖于低层次的模块他们都应该依赖于抽象。抽象不应该依赖于具体实现具体实现应该依赖于抽象。就是你出国要说你是中国人而不能说你是哪个村子的。比如说中国人是抽象的下面有具体的xx省xx市xx县。你要依赖的抽象是中国人而不是你是xx村的。接口分离原则ISP(the Interface Segregation Principle ISP) 设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。就比如一个手机拥有打电话看视频玩游戏等功能把这几个功能拆分成不同的接口比在一个接口里要好的多。
23、深拷贝和浅拷贝区别了解吗什么是引用拷贝 浅拷贝浅拷贝会在堆上创建一个新的对象区别于引用拷贝的一点不过如果原对象内部的属性是引用类型的话浅拷贝会直接复制内部对象的引用地址也就是说拷贝对象和原对象共用同一个内部对象。 深拷贝 深拷贝会完全复制整个对象包括这个对象所包含的内部对象。 引用拷贝 两个不同的引用指向同一个对象。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-34d6hOdk-1676522455028)(https://snailclimb.gitee.io/javaguide/docs/java/basis/images/shallowdeep-copy.png)]
24、String、StringBuffer、StringBuilder 的区别String 为什么是不可变的?
可变性
String内部的value值是final修饰的所以它是不可变类。所以每次修改String的值都会产生一个新的对象。StringBuffer和StringBuilder是可变类字符串的变更不会产生新的对象。
线程安全性
String是不可变类所以它是线程安全的。StringBuffer是线程安全的因为它每个操作方法都加了synchronized同步关键字。StringBuilder不是线程安全的所以在多线程环境下对字符串进行操作应该使用StringBuffer否则使用StringBuilder
性能
String的性能是最的低的因为不可变意味着在做字符串拼接和修改的时候需要重新创建新的对象以及分配内存。其次是StringBuffer要比String性能高因为它的可变性使得字符串可以直接被修改最后是StringBuilder它比StringBuffer的性能高因为StringBuffer加了同步锁。
存储方面
String存储在字符串常量池里面StringBuffer和StringBuilder存储在堆内存空间。
总结 操作少量的数据: 适用 String 单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder 多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer
25、字符串拼接用“” 还是 StringBuilder?
Java 语言本身并不支持运算符重载“”和“”是专门为 String 类重载过的运算符也是 Java 中仅有的两个重载过的元素符。
对象引用和“”的字符串拼接方式实际上是通过 StringBuilder 调用 append() 方法实现的拼接完成之后调用 toString() 得到一个 String 对象 。
不过在循环内使用“”进行字符串的拼接的话存在比较明显的缺陷编译器不会创建单个 StringBuilder 以复用会导致创建过多的 StringBuilder 对象。如果直接使用 StringBuilder 对象进行字符串拼接的话就不会存在这个问题了。
26、字符串常量池的作用了解吗
字符串常量池 是 JVM 为了提升性能和减少内存消耗针对字符串String 类专门开辟的一块区域主要目的是为了避免字符串的重复创建。
String aa ab; // 放在常量池中
String bb ab; // 从常量池中查找
System.out.println(aabb);// true27、final
final 有什么用
用于修饰类、属性和方法
被final修饰的类不可以被继承被final修饰的方法不可以被重写被final修饰的变量不可以被改变被final修饰不可变的是变量的引用而不是引用指向的内容引用指向的内容是可以改变的
final finally finalize区别
final可以修饰类、变量、方法修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。finally一般作用在try-catch代码块中在处理异常的时候通常我们将一定要执行的代码方法finally代码块中表示不管是否出现异常该代码块都会执行一般用来存放一些关闭资源的代码。finalize是一个方法属于Object类的一个方法而Object类是所有类的父类该方法一般由垃圾回收器来调用当我们调用System.gc() 方法的时候由垃圾回收器调用finalize()回收垃圾一个对象是否可回收的最后判断。
28、泛型
Java 泛型generics 是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型也就是说所操作的数据类型被指定为一个参数。
Java 的泛型是伪泛型这是因为 Java 在运行期间所有的泛型信息都会被擦掉这也就是通常所说类型擦除 。
泛型的分类
泛型一般有三种使用方式: 泛型类、泛型接口、泛型方法。
1.泛型类
//此处T可以随便写为任意标识常见的如T、E、K、V等形式的参数常用于表示泛型
//在实例化泛型类时必须指定T的具体类型
public class GenericT {private T key;public Generic(T key) {this.key key;}public T getKey() {return key;}
}Copy to clipboardErrorCopied如何实例化泛型类
GenericInteger genericInteger new GenericInteger(123456);Copy to clipboardErrorCopied2.泛型接口
public interface GeneratorT {public T method();
}Copy to clipboardErrorCopied实现泛型接口不指定类型
class GeneratorImplT implements GeneratorT{Overridepublic T method() {return null;}
}Copy to clipboardErrorCopied实现泛型接口指定类型
class GeneratorImpl implements GeneratorString{Overridepublic String method() {return hello;}
}Copy to clipboardErrorCopied3.泛型方法
public static E void printArray(E[] inputArray) {for (E element : inputArray) {System.out.printf(%s , element);}System.out.println();
}Copy to clipboardErrorCopied使用
// 创建不同类型数组 Integer, Double 和 Character
Integer[] intArray { 1, 2, 3 };
String[] stringArray { Hello, World };
printArray(intArray);
printArray(stringArray);Copy to clipboardErrorCopied常用的通配符有哪些
常用的通配符为 TEKV 表示不确定的 Java 类型T (type) 表示具体的一个 Java 类型K V (key value) 分别代表 Java 键值中的 Key ValueE (element) 代表 Element
你的项目中哪里用到了泛型 可用于定义通用返回结果 CommonResultT 通过参数 T 可根据具体的返回类型动态指定结果的数据类型 定义 Excel 处理类 ExcelUtilT 用于动态指定 Excel 导出的数据类型 用于构建集合工具类。参考 Collections 中的 sort, binarySearch 方法
29、反射
1、谈谈你对反射的理解
JAVA反射机制是在运行状态中对于任意一个类都能够知道这个类的所有属性和方法对于任意一个对象都能够调用它的任意一个方法和属性这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
2、反射机制优缺点
优点 增加程序的灵活性可以在运行的过程中动态对类进行修改和操作提高代码的复用率比如动态代理就是用到了反射来实现可以在运行时轻松获取任意一个类的方法、属性并且还能通过反射进行动态调用 缺点 反射会涉及到动态类型的解析所以JVM无法对这些代码进行优化导致性能要比非反射调用更低。使用反射以后代码的可读性会下降反射可以绕过一些限制访问的属性或者方法可能会导致破坏了代码本身的抽象性
3、反射的应用场景
①我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序
②Spring框架也用到很多反射机制 经典的就是xml的配置模式。Spring 通过 XML 配置模式装载 Bean 的过程1) 将程序内所有 XML 或 Properties 配置文件加载入内存中; 2)Java类里面解析xml或properties里面的内容得到对应实体类的字节码字符串以及相关的属性信息; 3)使用反射机制根据这个字符串获得某个类的Class实例; 4)动态配置实例的属性
另外像 Java 中的一大利器 注解 的实现也用到了反射。
为什么你使用 Spring 的时候 一个Component注解就声明了一个类为 Spring Bean 呢为什么你通过一个 Value注解就读取到配置文件中的值呢究竟是怎么起作用的呢
这些都是因为你可以基于反射分析类然后获取到类/属性/方法/方法的参数上的注解。你获取到注解之后就可以做进一步的处理。
30、注解
Annontation 注解 是Java5 开始引入的新特性可以看作是一种特殊的注释主要用于修饰类、方法或者变量。
注解本质是一个继承了Annotation 的特殊接口
Target(ElementType.METHOD)
Retention(RetentionPolicy.SOURCE)
public interface Override {}public interface Override extends Annotation{}Copy to clipboardErrorCopied注解只有被解析之后才会生效常见的解析方法有两种
编译期直接扫描 编译器在编译 Java 代码的时候扫描对应的注解并处理比如某个方法使用Override 注解编译器在编译的时候就会检测当前的方法是否重写了父类对应的方法。运行期通过反射处理 像框架中自带的注解(比如 Spring 框架的 Value 、Component)都是通过反射来进行处理的。
JDK 提供了很多内置的注解比如 Override 、Deprecated同时我们还可以自定义注解。
31、I/O
什么是序列化?什么是反序列化?
如果我们需要持久化 Java 对象比如将 Java 对象保存在文件中或者在网络传输 Java 对象这些场景都需要用到序列化。
简单来说
序列化 将数据结构或对象转换成二进制字节流的过程反序列化将在序列化过程中所生成的二进制字节流转换成数据结构或者对象的过程
对于 Java 这种面向对象编程语言来说我们序列化的都是对象Object也就是实例化后的类(Class)但是在 C这种半面向对象的语言中struct(结构体)定义的是数据结构类型而 class 对应的是对象类型。
维基百科是如是介绍序列化的 序列化serialization在计算机科学的数据处理中是指将数据结构或对象状态转换成可取用格式例如存成文件存于缓冲或经由网络中发送以留待后续在相同或另一台计算机环境中能恢复原先状态的过程。依照序列化格式重新获取字节的结果时可以利用它来产生与原始对象相同语义的副本。对于许多对象像是使用大量引用的复杂对象这种序列化重建的过程并不容易。面向对象中的对象序列化并不概括之前原始对象所关系的函数。这种过程也称为对象编组marshalling。从一系列字节提取数据结构的反向操作是反序列化也称为解编组、deserialization、unmarshalling。 综上序列化的主要目的是通过网络传输对象或者说是将对象存储到文件系统、数据库、内存中。 Java 序列化中如果有些字段不想进行序列化怎么办
对于不想进行序列化的变量使用 transient 关键字修饰。
transient 关键字的作用是阻止实例中那些用此关键字修饰的的变量序列化当对象被反序列化时被 transient 修饰的变量值不会被持久化和恢复。
关于 transient 还有几点注意
transient 只能修饰变量不能修饰类和方法。transient 修饰的变量在反序列化后变量值将会被置成类型的默认值。例如如果是修饰 int 类型那么反序列后结果就是 0。static 变量因为不属于任何对象(Object)所以无论有没有 transient 关键字修饰均不会被序列化。
获取用键盘输入常用的两种方法
方法 1通过 Scanner
Scanner input new Scanner(System.in);
String s input.nextLine();
input.close();Copy to clipboardErrorCopied方法 2通过 BufferedReader
BufferedReader input new BufferedReader(new InputStreamReader(System.in));
String s input.readLine();Copy to clipboardErrorCopiedJava 中 IO 流分为几种?
按照流的流向分可以分为输入流和输出流按照操作单元划分可以划分为字节流和字符流按照流的角色划分为节点流和处理流。
Java IO 流共涉及 40 多个类这些类看上去很杂乱但实际上很有规则而且彼此之间存在非常紧密的联系 Java IO 流的 40 多个类都是从如下 4 个抽象类基类中派生出来的。
InputStream/Reader: 所有的输入流的基类前者是字节输入流后者是字符输入流。OutputStream/Writer: 所有输出流的基类前者是字节输出流后者是字符输出流。
按操作方式分类结构图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x99o3fi0-1676522455030)(https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/IO-%E6%93%8D%E4%BD%9C%E6%96%B9%E5%BC%8F%E5%88%86%E7%B1%BB.png)]
按操作对象分类结构图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oS1276nI-1676522455031)(https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/IO-%E6%93%8D%E4%BD%9C%E5%AF%B9%E8%B1%A1%E5%88%86%E7%B1%BB.png)]
既然有了字节流,为什么还要有字符流?
问题本质想问不管是文件读写还是网络发送接收信息的最小存储单元都是字节那为什么 I/O 流操作要分为字节流操作和字符流操作呢
回答字符流是由 Java 虚拟机将字节转换得到的问题就出在这个过程还算是非常耗时并且如果我们不知道编码类型就很容易出现乱码问题。所以 I/O 流就干脆提供了一个直接操作字符的接口方便我们平时对字符进行流操作。如果音频文件、图片等媒体文件用字节流比较好如果涉及到字符的话使用字符流比较好
32、Java 中 3 种常见 IO 模型
BIO (Blocking I/O)
BIO 属于同步阻塞 IO 模型 。
同步阻塞 IO 模型中应用程序发起 read 调用后会一直阻塞直到内核把数据拷贝到用户空间。
在客户端连接数量不高的情况下是没问题的。但是当面对十万甚至百万级连接的时候传统的 BIO 模型是无能为力的。因此我们需要一种更高效的 I/O 处理模型来应对更高的并发量。
NIO (Non-blocking/New I/O)
Java 中的 NIO 于 Java 1.4 中引入对应 java.nio 包提供了 Channel , SelectorBuffer 等抽象。NIO 中的 N 可以理解为 Non-blocking不单纯是 New。它支持面向缓冲的基于通道的 I/O 操作方法。 对于高负载、高并发的网络应用应使用 NIO 。
Java 中的 NIO 可以看作是 I/O 多路复用模型。也有很多人认为Java 中的 NIO 属于同步非阻塞 IO 模型。
我们先来看看 同步非阻塞 IO 模型。
同步非阻塞 IO 模型中应用程序会一直发起 read 调用等待数据从内核空间拷贝到用户空间的这段时间里线程依然是阻塞的直到在内核把数据拷贝到用户空间。
相比于同步阻塞 IO 模型同步非阻塞 IO 模型确实有了很大改进。通过轮询操作避免了一直阻塞。
但是这种 IO 模型同样存在问题应用程序不断进行 I/O 系统调用轮询数据是否已经准备好的过程是十分消耗 CPU 资源的。
这个时候I/O 多路复用模型 就上场了。
IO 多路复用模型中线程首先发起 select 调用询问内核数据是否准备就绪等内核把数据准备好了用户线程再发起 read 调用。read 调用的过程数据从内核空间-用户空间还是阻塞的。 目前支持 IO 多路复用的系统调用有 selectepoll 等等。select 系统调用是目前几乎在所有的操作系统上都有支持 select 调用 内核提供的系统调用它支持一次查询多个系统调用的可用状态。几乎所有的操作系统都支持。epoll 调用 linux 2.6 内核属于 select 调用的增强版本优化了 IO 的执行效率。 IO 多路复用模型通过减少无效的系统调用减少了对 CPU 资源的消耗。
Java 中的 NIO 有一个非常重要的选择器 ( Selector ) 的概念也可以被称为 多路复用器。通过它只需要一个线程便可以管理多个客户端连接。当客户端数据到了之后才会为其服务。
AIO
也就是 NIO 2。Java 7 中引入了 NIO 的改进版 NIO 2,它是异步 IO 模型。
异步 IO 是基于事件和回调机制实现的也就是应用操作之后会直接返回不会堵塞在那里当后台处理完成操作系统会通知相应的线程进行后续的操作。
目前来说 AIO 的应用还不是很广泛。Netty 之前也尝试使用过 AIO不过又放弃了。这是因为Netty 使用了 AIO 之后在 Linux 系统上的性能并没有多少提升。
最后来一张图简单总结一下 Java 中的 BIO、NIO、AIO。 33、
34、和的区别
是位运算符。是布尔逻辑运算符在进行逻辑判断时用处理的前面为false后面的内容仍需处理用处理的前面为false不再处理后面的内容。
35、抽象类和接口的区别?
抽象类
抽象方法只有行为的概念没有具体的行为实现。使用abstract关键字修饰没有方法体。子类必须重写这些抽象方法。包含抽象方法的类一定是抽象类。抽象类只能被继承一个类只能继承一个抽象类。
接口 全部的方法都是抽象方法属型都是常量 不能实例化可以定义变量。 接口变量可以引用具体实现类的实例 接口只能被实现一个具体类实现接口必须实现全部的抽象方法 接口之间可以多实现 一个具体类可以实现多个接口实现多继承现象
36、this关键字的用法
this是自身的一个对象代表对象本身可以理解为指向对象本身的一个指针。
this的用法在java中大体可以分为3种
1.普通的直接引用this相当于是指向当前对象本身。
2.形参与成员名字重名用this来区分
3.引用本类的构造函数
37、super关键字的用法
super可以理解为是指向自己超父类对象的一个指针而这个超类指的是离自己最近的一个父类。
super也有三种用法
1.普通的直接引用
与this类似super相当于是指向当前对象的父类的引用这样就可以用super.xxx来引用父类的成员。
2.子类中的成员变量或方法与父类中的成员变量或方法同名时用super进行区分
3、引用父类构造函数
super参数调用父类中的某一个构造函数应该为构造函数中的第一条语句。this参数调用本类中另一种形式的构造函数应该为构造函数中的第一条语句。
38、是否了解连接池使用连接池有什么好处
数据库连接是非常消耗资源的影响到程序的性能指标。连接池是用来分配、管理、释放数据库连接的可以使应用程序重复使用同一个数据库连接而不是每次都创建一个新的数据库连接。通过释放空闲时间较长的数据库连接避免数据库因为创建太多的连接而造成的连接遗漏问题提高了程序性能。
39、hashCode与equals的相关规定 二、Java异常面试题
1、异常的含义
Java提供的一种识别及响应错误的一致性机制。
2、异常的作用
使程序中异常处理代码和正常业务代码分离保证代码更加优雅提高程序健壮性。
异常类型“什么被抛出”异常堆栈“在哪儿抛出”异常信息“为什么会抛出”。
3、运行时异常与一般异常
运行时异常一般异常虚拟机的通常操作中可能遇到的异常程序运行过程中可能出现的非正常状态Java编译器没有要求必须声明抛出Java编译器要求方法必须声明抛出可能发生的非运行时异常
4、 Error 和 Exception 区别是什么
Error 类型的错误通常为虚拟机相关错误如系统崩溃内存不足堆栈溢出等编译器不会对这类错误进行检测JAVA 应用程序也不应对这类错误进行捕获一旦这类错误发生通常应用程序会被终止仅靠应用程序本身无法恢复Exception 类的错误是可以在应用程序中进行捕获并处理的通常遇到这种错误应对其进行处理使应用程序可以继续正常运行。
5、throw 和 throws 的区别是什么
throw 关键字用在方法内部只能用于抛出一种异常用来抛出方法或代码块中的异常受查异常和非受查异常都可以被抛出。throws 关键字用在方法声明上可以抛出多个异常用来标识该方法可能抛出的异常列表。一个方法用 throws 标识了可能抛出的异常列表调用该方法的方法中必须包含可处理异常的代码否则也要在方法签名中用 throws 关键字声明相应的异常。
6、JVM如何处理异常
在一个方法中发生异常这个方法会创建一个异常对象转交给JVM(抛出)。可能有一系列的方法调用最终才进入抛出异常的方法这一系列的方法调用的有序列表叫做调用栈。
JVM会顺着调用栈去查看是否有可以处理异常的代码有则调用。若没有则将异常转交给默认的异常处理器默认异常处理器打印出异常信息并终止应用程序。
7、Java异常关键字
try监听监听包含的代码块若发生异常则抛出。
catch捕获异常捕获try抛出的异常。
finally语句块总会被执行用于回收在try块里打开的物力资源如数据库连接、网络连接、磁盘文件。
8、final、finally、finalize 有什么区别
final可以修饰类、变量、方法修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。finally一般作用在try-catch代码块中在处理异常的时候通常我们将一定要执行的代码方法finally代码块中表示不管是否出现异常该代码块都会执行一般用来存放一些关闭资源的代码。finalize是一个方法属于Object类的一个方法而Object类是所有类的父类Java 中允许使用 finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。
9、try-catch-finally 中如果 catch 中 return 了finally 还会执行吗 答会执行在 return 前执行。 注意 在 finally 中改变返回值的做法是不好的因为如果存在 finally 代码块try中的 return 语句不会立马返回调用者而是记录下返回值待 finally 代码块执行完毕之后再向调用者返回其值然后如果在 finally 中修改了返回值就会返回修改后的值。 10、 Java常见异常有哪些 三、Java集合面试题
1、集合概述
用于存储数据的容器。
2、集合框架
集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。
任何集合框架都包含三大块内容对外的接口、接口的实现和对集合运算的算法。
3、集合和数组的区别
数组集合长度固定可变存储类型基本数据类型、引用数据类型引用数据类型存储约束必须存储想同数据类型可以存储不同数据类型
4、List、Set两者的区别
List、Set都继承Collection,都是单链集合
ListSet无序无重复无索引有序有重复有索引可存入多个null只可存入一个null可以通过for循环、迭代器遍历只能通过迭代器遍历检索效率高检索效率低插入删除效率低因为会引起其他元素位置变化插入删除效率高
5、HashMap、HashTable、HashSet
Map键值对集合存储间、值之间的映射Key无序且唯一value不要求有序可重复常用接口为HashMap、HashTable
HashMapHashTabale性能高低线程不安全安全可否存null键和值都可为null不可迭代器不同
HashMapHashSet实现接口MapSet存储键值对对象添加元素put()add()hashCode计算使用建计算HashCode使用成员对象计算HashCode相同返回true性能快使用唯一的键获取对象慢
6、HashMap的存储原理
定义基于哈希表关联数组实现的Map。
原理
基于Hash算法通过put存储get取值。传入key值时根据key.hashCode()计算出hash值再根据hash值将value保存到bucket中。
优先使用数组存储。当计算的hash值相同时也就是hash冲突。此时转换为链表存储hash值相同的value。当链表长度大于8时为提高寻址速度改为红黑树存储。
7、迭代器lterator
作用提供遍历任何Collection的接口
特点单向遍历更加安全。若在遍历时集合元素被更改就会抛出异常。
8、ArrayList、LinkedList、Vector
ArrayListLinkedListVector结构基于动态数组基于链表基于动态数组擅长访问(get、set)移动数据新增、删除(add、remove)移动指针无线程不安全不安全安全性能强弱
9、集合框架底层数据结构
Collection List Arraylist Object数组LinkedList 双向循环链表Vector Object数组 Set HashSet无序唯一基于 HashMap 实现的底层采用 HashMap 来保存元素 LinkedHashSet LinkedHashSet 继承与 HashSet并且其内部是通过 LinkedHashMap 来实现的。有点类似于我们之前说的LinkedHashMap 其内部是基于 Hashmap 实现一样不过还是有一点点区别的。TreeSet有序唯一 红黑树(自平衡的排序二叉树。) Map HashMap JDK1.8之前HashMap由数组链表组成的数组是HashMap的主体链表则是主要为了解决哈希冲突而存在的“拉链法”解决冲突.JDK1.8以后在解决哈希冲突时有了较大的变化当链表长度大于阈值默认为8时将链表转化为红黑树以减少搜索时间LinkedHashMapLinkedHashMap 继承自 HashMap所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外LinkedHashMap 在上面结构的基础上增加了一条双向链表使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作实现了访问顺序相关逻辑。HashTable 数组链表组成的数组是 HashMap 的主体链表则是主要为了解决哈希冲突而存在的TreeMap 红黑树自平衡的排序二叉树
10、怎么确保一个集合不能被修改 12、迭代器 Iterator 是什么
Iterator 接口提供遍历任何 Collection 的接口。我们可以从一个 Collection 中使用迭代器方法来获取迭代器实例。迭代器取代了 Java 集合框架中的 Enumeration迭代器允许调用者在迭代过程中移除元素。因为所有Collection接口继承了Iterator迭代器
13、Iterator 和 ListIterator 有什么区别
Iterator 可以遍历 Set 和 List 集合而 ListIterator 只能遍历 List。Iterator 只能单向遍历而 ListIterator 可以双向遍历向前/后遍历。ListIterator 实现 Iterator 接口然后添加了一些额外的功能比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。
14、List和Set的区别
List: 有序按对象进入的顺序保存对象可重复,允许多个Null元素对象可以使用Iterator取出所有元素,在逐个遍历,还可以使用get(int index)获取指定下标的元素Set: 无序,不可重复,最够允许有一个Null元素对象,取元素时只能用Iterator接口取得所有元素在逐一遍历各个元素
15、ArrayList和LinkedList的区别 16、HashMap和hasptable有什么区别
从功能特性的角度来说HashTable是线程安全的而HashMap不是。HashMap的性能要比HashTable更好因为HashTable采用了全局同步锁来保证安全性对性能影响较大从内部实现的角度来说HashTable使用数组加链表、HashMap采用了数组链表红黑树。HashMap初始容量是16、HashTable初始容量是11HashMap可以使用null作为keyHashMap会把null转化为0进行存储而Hashtable不允许。最后他们两个的key的散列算法不同HashTable直接是使用key的hashcode对数组长度做取模。而HashMap对key的hashcode做了二次散列从而避免key的分布不均匀问题影响到查询性能。 17、说一下HashMap的Put方法
先说HashMap的Put方法的大体流程:
根据Key通过哈希算法与与运算得出数组下标如果数组下标位置元素为空,则将key和value封装为Entry对象 (JDK1.7中是Entry对象, JDK1.8中是Node对象)并放入该位置如果数组下标位置元素不为空则要分情况讨论 如果是JDK1.7,则先判断是否需要扩容,如果要扩容就进行扩容如果不用扩容就生成Entry对象,并使用头插法添加到当前位置的链表中 如果是JDK1.8,则会先判断当前位置上的Node的类型看是红黑树Node,还是链表Node如果是红黑树Node,则将key和value封装为一个红黑树节点并添加到红黑树中去在这个过程中会判断红黑树中是否存在当前key,如果存在则更新value如果此位置上的Node对象是链表节点则将key和value封装为一 个链表Node并通过尾插法插入到链表的最后位置去因为是尾插法,所以需要遍历链表,在 遍历链表的过程中会判断是否存在当前key,如果存在则更新vatue,当遍历完链表后将新链表Node插入到链表中,插入到链表后会看当前链表的节点个 数,如果大于等于8,那么则会将该链表转成红黑树将key和value封装为Node插入到链表或红黑树中后再判断是否需要进行扩容,如果需要就扩容,如果不需要就结束PUT方法
18、HashMap的扩容机制原理
1.7版本
1.先生成新数组 2.遍历原来数组中的每个位置上的链表上的每个元素 3.取每个元素 的key,并基于新数组长度计算出每个元素在新数组中的下标 4.将元素添加到新数组中去 5.所有元素转移完了之后将新数组赋值给HashMap对象的table属性
1.8版本
先生成新数组遍历原来数组中的每个位置上的链表或红黑树如果是链表则直接将链表中的每个元索重新计算下标,并添加到新数组中去如果是红黑树则先遍历红黑树先计算出红黑树中每个元索元素在新数组中的下标位置。 统计每个下标位置的元素个数如果该位置下的元素个数超过了8,则生成一个新的红黑树并将根节点的添加到新数组的对应位置如果该位置下的元素个数没有超过8,那么则生成一个链表, 并将链表的头节点添加到新数组的对应位置
5.所有元素转移完了之后,将新数组赋值给HashMap对象的table属性
19、说一下 ArrayList 的优缺点 ArrayList的优点如下 ArrayList 底层以数组实现是一种随机访问模式。ArrayList 实现了 RandomAccess 接口因此查找的时候非常快。ArrayList 在顺序添加一个元素的时候非常方便。 ArrayList 的缺点如下 删除元素的时候需要做一次元素复制操作。如果要复制的元素很多那么就会比较耗费性能。插入元素的时候也需要做一次元素复制操作缺点同上。ArrayList 比较适合顺序添加、随机访问的场景。 ArrayList的扩容机制 默认情况下新的容量会是原容量的1.5倍。 新容量旧容量右移一位相当于除于2在加上旧容量 ArrayList 的底层是用动态数组来实现的。我们初始化一个ArrayList 集合还没有添加元素时其实它是个空数组只有当我们添加第一个元素时内部会调用扩容方法并返回最小容量10也就是说ArrayList 初始化容量为10。 当前数组长度小于最小容量的长度时前期容量是10当添加第11个元素时就就扩容便开始可以扩容了ArrayList 扩容的真正计算是在一个grow()里面新数组大小是旧数组的1.5倍如果扩容后的新数组大小还是小于最小容量那新数组的大小就是最小容量的大小后面会调用一个Arrays.copyof方法这个方法是真正实现扩容的步骤。
20、如何实现数组和 List 之间的转换
数组转 List使用 Arrays. asList(array) 进行转换List 转数组使用 List 自带的 toArray() 方法。
21、ArrayList 和 Vector 的区别是什么 22、说一下 HashSet 的实现原理 HashSet 是基于 HashMap 实现的HashSet的值存放于HashMap的key上HashMap的value统一为present因此 HashSet 的实现比较简单相关 HashSet 的操作基本上都是直接调用底层 HashMap 的相关方法来完成HashSet 不允许重复的值。 23、 HashSet如何检查重复HashSet是如何保证数据不可重复的
向HashSet 中add ()元素时判断元素是否存在的依据不仅要比较hash值同时还要结合equles 方法比较。HashSet 中的add ()方法会使用HashMap 的put()方法。HashMap 的 key 是唯一的由源码可以看出 HashSet 添加进去的值就是作为HashMap 的key并且在HashMap中如果K/V相同时会用新的V覆盖掉旧的V然后返回旧的V。所以不会重复 HashMap 比较key是否相等是先比较hashcode 再比较equals 。
24、说一下HashMap的实现原理 25、HashMap在JDK1.7和JDK1.8中有哪些不同HashMap的底层实现
HashMap JDK1.8之前 JDK1.8之前采用的是拉链法。拉链法将链表和数组相结合。也就是说创建一个链表数组数组中每一格就是一个链表。若遇到哈希冲突则将冲突的值加到链表中即可。
HashMap JDK1.8之后
相比于之前的版本jdk1.8在解决哈希冲突时有了较大的变化当链表长度大于阈值默认为8时将链表转化为红黑树以减少搜索时间。 26、说说什么是红黑树 27、能否使用任何类作为 Map 的 key 28、HashMap 的长度为什么是2的幂次方 29、HashMap 与 HashTable 有什么区别 30、Array 和 ArrayList 有何区别
Array 可以存储基本数据类型和对象ArrayList 只能存储对象。Array 是指定固定大小的而 ArrayList 大小是自动扩展的。Array 内置方法没有 ArrayList 多比如 addAll、removeAll、iteration 等方法只有 ArrayList 有。
31、comparable 和 comparator的区别
comparable接口实际上是出自java.lang包它有一个 compareTo(Object obj)方法用来排序comparator接口实际上是出自 java.util 包它有一个compare(Object obj1, Object obj2)方法用来排序一般我们需要对一个集合使用自定义排序时我们就要重写compareTo方法或compare方法当我们需要对某一个集合实现两种排序方式比如一个song对象中的歌名和歌手名分别采用一种排序方法的话我们可以重写compareTo方法和使用自制的Comparator方法或者以两个Comparator来实现歌名排序和歌星名排序第二种代表我们只能使用两个参数版的Collections.sort().
32、Collection和Collections有什么区别
java.util.Collection 是一个集合接口集合类的一个顶级接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式其直接继承接口有List与Set。Collections则是集合类的一个工具类/帮助类其中提供了一系列静态方法用于对集合中元素进行排序、搜索以及线程安全等各种操作。
四、Java线程面试题
1、为什么要使用多线程
1充分发挥多核CPU的优势
2防止程序阻塞
3便于建模。
2、单线程和多线程的区别。
1单核CPU中每个时间片段只能有一个线程运行。
2单线程程序执行效率更快多线程用户响应时间更少。
3、进程和线程
进程程序有指令和数据的文件的一次执行过程。
线程轻量级进程。进程的组成单元。同类多个线程共享同一块内存空间和一组资源。
4、并行和并发
并发一个CPU在多个线程之间快速切换达到同时执行多个任务的目的。
并行多个CPU可以同时执行一个进程中的多个线程。
5、线程的创建方式
方法一继承Thread类作为线程对象存在继承Thread对象
方法二实现runnable接口作为线程任务存在
方法三匿名内部类创建线程对象
方法四创建带返回值的线程
方法五定时器Timer
方法六线程池创建线程
方法七利用java8新特性stream 实现并发
让线程等待的方法
Thread.sleep(200); //线程休息2ms
Object.wait() //让线程进入等待直到调用Object的notify或者notifyAll时线程停止休眠
6、线程的六种状态
1初始状态线程构建但还没有调用start()方法。
2运行状态操作系统中的“就绪”和“运行”。
3阻塞状态线程阻塞于锁。
4等待状态当前线程需要等待其他线程做出特定动作通知/中断。
5超时等待状态在特定的时间自行返回。
6终止状态当前线程已执行完毕。 7、如何停止一个正在运行的线程
1使用推出标致当run()方法完成后线程终止正常退出。
2使用stop方法强行终止不推荐过期作废。
3使用interrupt方法中断线程
8、start()和run()方法的区别
Start()调用后才能出现多线程的特性不同线程的run()方法里面的代码交替执行。
run()如果调用后代码还是同步执行的必须等待一个线程的run()方法里的代码全部执行完毕另一个run()才能开始执行。
9、为什么调用start()方法的时候会执行run()方法而不能直接调用run()方法
JVM执行start方法会令其一条线程执行继承的thread的run方法这才起到多线程的效果。
如果直接调用thread的run方法其方法还是在运行的主线程中没有起到多线程的效果。
10、什么是线程安全
多线程访问同一代码而不会产生不确定的结果。
11、Java中堆和栈的区别
栈在函数中定义的基本类型的变量和对象的引用变量都在函数的栈内存中。用来存放执行程序
堆用于存放由new创建的对象和数组。
12、如何确保线程安全
1对非安全的代码进行“加锁”。
2使用线程安全的类。
3多线程高并发情况下线程共享的变量改为“方法级的局部变量”。
13、线程的安全级别
线程安全在多 线程下执行和在单线程下执行永远都能获得一样的结果那么你的代码就是线程安全的。
1不可变不可变的对象一定是线程安全的永远也不需要额外的同步。
2无条件的线程安全由类的规格说明所规定的的约束在对象被多个线程访问时仍然有效不管运行时环境如何排列线程都不需要额外的同步。
3有条件的线程安全有条件的线程安全类对于单独的操作可以是线程安全但是某些操作序列可能需要额外的同步。
4非线程安全线程兼容线程兼容类不是线程安全的但是可以通过正确使用同步在并发环境中安全地使用。
5线程对立是那些不管是否采用了“同步措施”都不能在多线程环境中并发使用的代码。
14、线程类的构造方法和静态块是被哪个线程调用的
是被new这个线程类所在的线程所调用的而run里面的代码才是被线程自身调用。
15、线程池的作用
1降低资源消耗。重复利用已创建的线程降低线程创建和销毁所造成的消耗
2提高响应速度。任务到达时任务可以不需要等到线程创建就能立即执行
3提高线程的可管理性。线程是稀缺资源如果无限制的创建不仅会消耗系统资源还会降低系统的稳定性使用线程池可以进行同一的分配调优和监控
16、Java中的死锁问题
死锁死锁是指两个或两个以上的进程线程在执行过程中由于竞争资源或者由于彼此通信而造成的一种阻塞的现象若无外力作用它们都将无法推进下去。
必要条件
1互斥条件进程对所分配到的资源进行排他性使用。
2请求和保持条件进程已经保持至少一个资源但又提出了新的资源请求而该资源已经被其他进程占有。
3不剥夺条件进程已获得的资源在未使用完之前不能被剥夺。
4环路等待条件在发生死锁时必然存在一个进程–资源的环形链。
如何解决死锁问题
程序出现死锁是因为在多线程环境里面两个或两个以上的线程同时满足互斥条件、请求保持条件、不可抢占条件、循环等待条件。出现死锁以后可以通过jstack命令去导出线程的dump日志然后从dump日志里面定位到具体死锁的程序代码。通过修改程序代码去破坏这四个条件里面的任意一个就可以解决死锁问题。当然因为互斥条件因为是锁本身的特性所以不能被破坏。
17、如何避免死锁和检测
1预防死锁破坏互斥关系、破坏请求和保持条件、破坏不剥夺条件、破坏循环等待条件。
2设置加锁顺序。
破坏互斥关系无法破坏临界资源需要互斥访问破坏请求和保持条件一次性申请所有的资源破坏不剥夺条件占用部分资源的线程进一步申请其他资源时若申请不到则主动释放它占有的资源破坏循环等待条件靠按序申请资源来预防。按某一顺序申请资源释放资源则反序释放。
18、synchronized底层原理
同步代码块
synchronized(锁对象){需要同步执行的代码
}原理一旦线程进入了该代码块就持有锁JVM会有监视器监视进入锁的线程其他线程想进入代码监视器就会拒绝访问一旦持有锁的线程执行完代码锁就会被释放其他线程才可进入。
注意任何对象都可以作为锁必须是成员变量。
19、生产者消费者模型的作用是什么
1平衡生产者的生产能力和消费者的消费能力提升整个系统的运行效率。
2解耦。
20、生产者消费者模式
生产者是生产数据的线程消费者是消费数据的线程。
如果生产者处理速度远快过消费数据的速度那么生产者必须等待消费者处理完才能继续生产数据。
反之如果消费者的处理能力大于生产者那么消费者就必须等待生产者。为了解决这种生产消费能力不均衡的问题所以便有了生产者和消费者模式。
21、创建线程池的几种方法
方式一通过构造方法实现
方式二通过****Executor 框架的工具类Executors来实现 我们可以创建三种类型的
返回线程数量无限的线程池ExecutorService newCachedThreadPool()返回固定长度的线程池好处是可以控制并发量ExecutorService newFixedThreadPool(int size)返回单一线程的线程池ExecutorService newSingleThreadExecutor()返回可以调度的线程池ScheduledExecutorService newScheduledThreadPool(int size)
22、自定义线程池的配置
ThreadPoolExecutor的构造方法
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueueRunnable workQueue)参数说明
corePoolSize核心线程数maximumPoolSize最大线程数keepAliveTime临时的线程能够存活的时间unit时间单位workQueue用于保存任务的阻塞队列
优化配置 核心线程数大于或等于CPU内核的数量如果是CPU密集型任务就需要尽量压榨CPU参考值可以设为 NCPU1如果是IO密集型任务参考值可以设置为2*NCPU获得CPU的内核数Runtime.getRuntime().availableProcessors() 最大线程数和核心线程数配置一样性能比较高因为避免临时线程的创建和销毁 如果临时线程比较多可以将存活时间配置稍微长点减少临时线程的创建和销毁 4、阻塞队列LinkedBlockingQueue的性能比较高
23、什么是乐观锁和悲观锁
悲观锁 想法悲观认为当前的资源存在竞争所以每次获得资源时都会上锁阻塞住其它线程。 数据库中的行锁、表锁、读锁、写锁都属于悲观锁Java的synchronized和ReentrantLock也属于悲观锁。 悲观锁会降低系统性能和吞吐量提高数据的安全性适用于多写少读的场景。乐观锁 想法乐观认为当前的资源不存在竞争所以每次获得资源时都不上锁 乐观锁执行效率高有利于提高系统吞吐量适用于多读少写的场景。
24、并发编程三要素是什么在Java程序中怎么保证多线程的运行安全
三要素出现安全问题的原因解决办法原子性一个或多个操作要么全部执行要么全部执行失败。线程切换JDK Atomic开头的原子类、synchronized、LOCK可以解决原子性问题可见性一个线程对共享变量的修改另一个线程能够立刻看到。缓存导致synchronized、volatile、LOCK可以解决可见性问题有序性程序执行的顺序按照代码的先后顺序执行。编译优化Happens-Before 规则可以解决有序性问题
25、volatile 关键字
用来确保将变量的更新操作通知到其他线程。可以将 volatile 看做一个轻量级的锁但是又与锁有些不同
对于多线程不是一种互斥关系不能保证变量状态的“原子性操作”
被volatile修饰的共享变量就具有了以下两点特性
1.保证了不同线程对该变量操作的内存可见性;2.禁止指令重排序
26、乐观锁如何实现
乐观锁常用的两种实现方式
版本号机制 利用版本号version记录数据被修改的次数当数据被修改时version加一。当线程要更新数据值时在读取数据的同时也会读取version值在提交更新时若刚才读取到的version值为当前version值相等时才更新否则重试更新操作直到更新成功。CAS算法 Compare and Swap比较与交换 CAS涉及三个操作数 读写变量的内存位置预期值写入的新值 CAS实现过程是先判断内存位置上的值是否和预期值一致如果一致就修改为新值否则不执行。
27、sleep方法和wait方法有什么区别和共同点
两者最主要的区别在于sleep() 方法没有释放锁而 wait() 方法释放了锁 。 两者都可以暂停线程的执行。 wait() 通常被用于线程间交互/通信sleep() 通常被用于暂停执行。 wait() 方法被调用后线程不会自动苏醒需要别的线程调用同一个对象上的 notify() 或者 notifyAll() 方法。sleep() 方法执行完成后线程会自动苏醒。或者可以使用 wait(long timeout) 超时后线程会自动苏醒。
28、CAS算法
CAS (Compare-And-Swap 比较与交换) 是一种硬件对并发的支持针对多处理器操作而设计的处理器中的一种特殊指令用于管理对共享数据的并发访问。
CAS 是一种无锁的非阻塞算法的实现。CAS 包含了 3 个操作数需要读写的内存值 V、进行比较的值 A、拟写入的新值 B当且仅当 V 的值等于 A 时CAS 通过原子方式用新值 B 来更新 V 的值否则不会执行任何操作。
这是一个模拟实现是通过synchronizes加锁的阻塞算法跟真正的CAS不同。
五、Java虚拟机面试题 1、什么是Java虚拟机为何被称作“平台无关的编程语言”
Java虚拟机是一个可以执行Java字节码.class的虚拟机进程。
Java源文件.java被编译成Java字节码.class。允许应用程序可以在任意平台。
因为Java虚拟机知道底层硬件平台的指令长度和其他特性。
2、Java的内存结构
1Java堆虚拟机启动时创建存放对象实例new。各线程共享。
2方法区存储加载的类的信息、常量、静态变量、编译后的代码等。各线程共享。
3程序计数器当前线程所执行的字节码的行号指示器。线程私有。
4JVM栈描述Java方法执行的内存模型每个栈帧对应一个方法线程私有。
5本地方法栈为虚拟机使用到的Native方法服务。 Java虚拟机会出现的两种错误
StackOverFlowError 若Java虚拟机栈的内存大小不允许动态扩展那么当线程请求栈的深度超过当前Java虚拟机栈的最大深度的时候就抛出StackOverFlowError 错误。OutOfMemoryError若Java虚拟机栈的内存大小允许动态扩展且当线程请求栈时内存用完了无法再动态扩展了此时抛出 OutOfMemoryError错误。
扩展那么方法/函数如何调用 Java 栈可用类比数据结构中栈Java 栈中保存的主要内容是栈帧 每一次函数调用都会有一个对应的栈帧被压入 Java 栈 每一个函数调用结束后都会有一个栈帧被弹出。Java 方法有两种返回方式 return 语句。 抛出异常。不管哪种返回方式都会导致栈帧被弹出。 3、内存分配
1寄存器无法控制。
2静态域static定义的成员。
3常量池编译时被确定并保存到.class文件中的final常量值和一些文本修饰的符号引用。
4非RAM存储硬盘等永久存储空间。
5堆内存new创建的对象和数组由Java虚拟机自动垃圾回收器管理存取速度慢。
栈内存基本类型的变量和对象的引用变量对内存空间的访问地址速度快可以共享但是大小与生存周期必须确定缺乏灵活性。
4、类加载器
1启动类加载器负责加载JDK\jre\lib下的文件。
2扩展类加载器负责加载JDK\jre\lib\ext目录中的所有类库。
3应用程序类加载器负责加载用户类路径所指定的类。
5、JVM如何加载class文件
类加载器运行时查找和装入类文件中的类。
加载把类的.class文件中的数据读入到内存之中通过创建字节数组读入.class文件然后产生与所加载类对应的Class对象。
连接验证、准备为静态变量分配内存并设置默认的初始值和解析。
初始化1如果类存在直接的父类且这个父类还没有被初始化则先初始化父类。
2如果类中存在初始化语句就依次执行这些初始化语句。
6、Java对象创建的过程
1拿到内存创建的指令new 类名来到方法区根据new的参数在常量池找到一个类的符号引用。
2检查符号引用检查是否被加载、解析和初始化过。
3分配内存。
4初始化抽象数据类型默认初始化为null基本数据类型为0布尔为false…
5调用对象的初始化方法。 7、Java对象的结构
1对象头运行时数据、指针类型。
2实例数据存储对象真正的有效信息。
3对齐填充要求对象初始地址必须是8字节的整数倍。
8、类的生命周期
加载根据查找路径找到相应的 class 文件然后导入验证检查加载的 class 文件的正确性准备给类中的静态变量分配内存空间解析虚拟机将常量池中的符号引用替换成直接引用的过程。符号引用就理解为一个标示而在直接引用直接指向内存中的地址初始化对静态变量和静态代码块执行初始化工作。
9、什么情况下会发生栈溢出
栈的大小可以通过-Xss参数设置当递归层次太深的时候就会发生栈溢出。例循环、递归。
10、Java垃圾回收机制,GC是什么为什么要GC?
Java垃圾回收机制低优先级只有在JVM空闲和当前堆内存不足时会执行。扫描出那些没有被引用过的类将他们添加到要回收的集合中进行回收。
GC 是垃圾收集的意思。
Java 提供的 GC 功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的。
11、JVM新生代、老年代、持久代都存储些哪些东西
1新生代new出的对象。
2老年代新生代中经历了N次垃圾回收仍存活的对象、大对象直接存入、Survivor空间不足。
3持久代指方法区。
12、Java会存在内存泄漏吗
内存泄漏指一个不再被程序使用的对象或变量一直被占据在内存中。
情况长生命周期的对象只有断声明周期对象的引用时可能发生内存泄漏。对生命周期对象已经不需要但是因为长生命周期对象对其的引用而无法回收。
13、JVM调优有哪些
1设定堆内存大小。-Mmx堆内存最大限制。
2设定新生代大小不能太小否则会大量涌入老年代
-XX:NewSize新生代大小
-XX:NewRatio新生代和老生代占比
-XX:SurvivorRatio伊甸园空间和幸存者空间占比
3设定垃圾回收器年轻代-XX:UseParNewGC
老年代-XX:UseConcMarkSweepGC
说一下 JVM 调优的工具
JDK 自带了很多监控工具都位于 JDK 的 bin 目录下其中最常用的是 jconsole 和 jvisualvm 这两款视图监控工具。
jconsole用于对 JVM 中的内存、线程和类等进行监控jvisualvmJDK 自带的全能分析工具可以分析内存快照、线程快照、程序死锁、监控内存的变化、gc 变化等。
14、如何判断对象可以被回收
引用计数法 在JDK1.2之前使用的是引用计数器算法。在对象中添加一个引用计数器当有地方引用这个对象的时候引用计数器的值就1当引用失效的时候计数器的值就-1当引用计数器被减为零的时候标志着这个对象已经没有引用了可以回收了 可达性分析法 通过一系列的称为 GC Roots 的对象作为起点, 然后向下搜索; 搜索所走过的路径称为引用链/Reference Chain, 当一个对象到 GC Roots 没有任何引用链相连时, 即该对象不可达, 也就说明此对象是不可用的。
15、 JVM的永久代中会发生垃圾回收么
垃圾回收不会发生在永久代如果永久代满了或者是超过了临界值会触发完全垃圾回收Full GC。
注Java 8 中已经移除了永久代新加了一个叫做元数据区的native 内存区。
16、栈帧有哪些数据
每个线程栈里的元素就是“栈帧”。
局部变量表、操作数栈、动态连接、返回地址。
17、Java的双亲委托机制是什么 每一个类都有一个对应它的类加载器。系统中的 ClassLoder 在协同工作的时候会默认使用 双亲委派模型 。即在类加载的时候系统会首先判断当前类是否被加载过。已经被加载的类会直接返回否则才会尝试加载。加载的时候首先会把该请求委派该父类加载器的 loadClass() 处理因此所有的请求最终都应该传送到顶层的启动类加载器 BootstrapClassLoader 中。当父类加载器无法处理时才由自己来处理。当父类加载器为null时会使用启动类加载器 BootstrapClassLoader 作为父类加载器。 18、说一下堆栈的区别
栈堆物理地址栈使用的是数据结构中的栈先进后出的原则物理地址分配是连续的。所以性能快。堆的物理地址分配对对象是不连续的。因此性能慢些。内存分别栈是连续的所以分配的内存大小要在编译期就确认大小是固定的。堆因为是不连续的所以分配的内存是在运行期确认的因此大小不固定。一般堆大小远远大于栈。存放的内容栈存放局部变量操作数栈返回结果。该区更关注的是程序方法的执行。堆存放的是对象的实例和数组。因此该区更关注的是数据的存储PS静态变量放在方法区静态的对象还是放在堆。程序的可见度栈只对于线程是可见的。所以也是线程私有。他的生命周期和线程相同。堆对于整个应用程序都是共享、可见的。
19、队列和栈是什么有什么区别
队列和栈都是被用来预存储数据的。
队列栈操作的名称队列的插入称为入队队列的删除称为出队。栈的插入称为进栈栈的删除称为出栈。可操作的方式队列是在队尾入队队头出队即两边都可操作。而栈的进栈和出栈都是在栈顶进行的无法对栈底直接进行操作。操作的方法队列是先进先出FIFO即队列的修改是依先进先出的原则进行的。新来的成员总是加入队尾不能从中间插入每次离开的成员总是队列头上不允许中途离队。而栈为后进先出LIFO,即每次删除出栈的总是当前栈中最新的元素即最后插入进栈的元素而最先插入的被放在栈的底部要到最后才能删除。
20、为对象分配内存
指针碰撞如果Java堆的内存是规整即所有用过的内存放在一边而空闲的的放在另一边。分配内存时将位于中间的指针指示器向空闲的内存移动一段与对象大小相等的距离这样便完成分配内存工作。 空闲列表如果Java堆的内存不是规整的则需要由虚拟机维护一个列表来记录那些内存是可用的这样在分配的时候可以从列表中查询到足够大的内存分配给对象并在分配后更新列表记录。 21、处理并发安全问题
对分配内存空间的动作进行同步处理采用 CAS 失败重试来保障更新操作的原子性 把内存分配的动作按照线程划分在不同的空间之中进行即每个线程在 Java 堆中预先分配一小块内存称为本地线程分配缓冲Thread Local Allocation Buffer, TLAB。哪个线程要分配内存就在哪个线程的 TLAB 上分配。只有 TLAB 用完并分配新的 TLAB 时才需要同步锁。通过-XX:/-UserTLAB参数来设定虚拟机是否使用TLAB。
22、说一下 JVM 有哪些垃圾回收算法 标记-清除算法标记无用对象然后进行清除回收。缺点效率不高无法清除垃圾碎片。 优点解决了标记-清理算法存在的内存碎片问题。缺点仍需要进行局部对象移动一定程度上降低了效率。 复制算法按照容量划分二个大小相等的内存区域当一块用完的时候将活着的对象复制到另一块上然后再把已使用的内存空间一次清理掉。缺点内存使用率不高只有原来的一半。 适用于新生代。 优点按顺序分配内存即可实现简单、运行高效不用考虑内存碎片。优点解决了标记-清理算法存在的内存碎片问题。可用的内存大小缩小为原来的一半对象存活率高时会频繁进行复制。 标记-整理算法标记无用对象让所有存活的对象都向一端移动然后直接清除掉端边界以外的内存。适用于老年代。 优点解决了标记-清理算法存在的内存碎片问题。缺点仍需要进行局部对象移动一定程度上降低了效率。 分代算法根据对象的存活周期将内存划分为几块。一般包括年轻代、老年代 和 永久代新生代基本采用复制算法老年代采用标记整理算法。
23、分代概念
新生成的对象首先放到年轻代Eden区当Eden空间满了触发Minor GC存活下来的对象移动到Survivor0区Survivor0区满后触发执行Minor GCSurvivor0区存活对象移动到Suvivor1区这样保证了一段时间内总有一个survivor区为空。经过多次Minor GC仍然存活的对象移动到老年代。 老年代存储长期存活的对象占满时会触发Major GCFull GCGC期间会停止所有线程等待GC完成所以对响应要求高的应用尽量减少发生Major GC避免响应超时。 Minor GC 清理年轻代 Major GC 清理老年代 Full GC 清理整个堆空间包括年轻代和永久代 所有GC都会停止应用所有线程。
24、为什么分代
将对象根据存活概率进行分类对存活时间长的对象放到固定区从而减少扫描垃圾时间及GC频率。针对分类进行不同的垃圾回收算法对算法扬长避短。
25、JVM堆内存常用参数
参数描述-Xms堆内存初始大小单位m、g-XmxMaxHeapSize堆内存最大允许大小一般不要大于物理内存的80%-XX:PermSize非堆内存初始大小一般应用设置初始化200m最大1024m就够了-XX:MaxPermSize非堆内存最大允许大小-XX:NewSize-Xns年轻代内存初始大小-XX:MaxNewSize-Xmn年轻代内存最大允许大小也可以缩写-XX:SurvivorRatio8年轻代中Eden区与Survivor区的容量比例值默认为8即8:1-Xss堆栈内存大小
26、类加载的过程
JVM的类加载分为5个阶段加载、验证、准备、解析、初始化。在类初始化完成后就可以使用该类的信息在一个类不再被需要时可以从JVM中卸载 加载 指JVM读取Class文件并且根据Class文件描述创建java. lang. Class对象的过程。类加载过程主要包含将Class文件读取到运行时区域的方法区内在堆中创建java.lang.Class 对象并封装类在方法区的数据结构的过程在i卖取Class文件时既可以通过文件的形式读取也可以通过jar包、war包读取还可以通过代理自动生成Class或其他方式读取。 验证 主要用于确保Class文件符合当前虚拟机的要求保障虚拟机自身的安全只有通过验证的Class文件才能被JVM加载。 准备 主要工作是在方法区中为类变量分配内存空间并设置类中变量的初始值。初始值指不同数据类型的默认值这里需要注意final类型的变量和非final类型的变量在准备阶段的数据初始化过程不同。 解析 JVM会将常量池中的符号引用替换为直接引用。 初始化 要通过执行类构造器的client方法为类进行初始化。client方法是在编译阶段由编译器自动收集类中静态语句块和变量的赋值操作组成的。JVM规定只有在父类的client方法都执行成功后子类中的client方法才可以被执行。在一个类中既没有静态变量赋值操作也没有静态语句块时编译器不会为该类生成client方法
27、Java中的4种引用类型
强引用在Java中最常见的就是强引用。在把一个对象赋给一个引用变量时这个引用变量就是一个强引用。有强引用的对象一定为可达性状态所以不会被垃圾回收机制回收。因此强引用是造成Java内存泄漏Memory Link 的主要原因。软引用软引用通过SoftReference类实现。如果一个对象只有软引用则在系统内存空间不足时该对象将被回收。弱引用弱引用通过WeakReference类实现如果一个对象只有弱引用则在垃圾回收过程中一定会被回收。虚引用虚引用通过PhantomReference类实现虚引用和引用队列联合使用主要用于跟踪对象的垃圾回收状态。
六、MySQL面试题
1、什么是MySQL
MySQL是一个关系型数据库管理系统由瑞典MySQL AB 公司开发属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一在 WEB 应用方面MySQL是最好的 RDBMS (Relational Database Management System关系数据库管理系统) 应用软件之一。在Java企业级开发中非常常用因为 MySQL 是开源免费的并且方便扩展。
2、数据库三大范式
第一范式每个列都不可以再拆分。第二范式在第一范式的基础上非主键列完全依赖于主键而不能是依赖于主键的一部分。第三范式在第二范式的基础上非主键列只依赖于主键不依赖于其他非主键。
在设计数据库结构的时候要尽量遵守三范式如果不遵守必须有足够的理由。比如性能。事实上我们经常会为了性能而妥协数据库的设计。
3、对慢查询怎么样优化过
1分析语句看是否查询了多余的行并且抛弃掉了是否加载了许多结果中不需要的列对语句进行分析以及重写
2分析语句的执行计划获得其使用索引的情况进行修改使语句可以尽可能的命中索引
3考虑数据量是否太大可以考虑进行横向或者纵向分表。
4、mysql有关权限的表都有哪几个
MySQL服务器通过权限表来控制用户对数据库的访问权限表存放在mysql数据库里由mysql_install_db脚本初始化。这些权限表分别userdbtable_privcolumns_priv和host。下面分别介绍一下这些表的结构和内容
user权限表记录允许连接到服务器的用户帐号信息里面的权限是全局级的。db权限表记录各个帐号在各个数据库上的操作权限。table_priv权限表记录数据表级的操作权限。columns_priv权限表记录数据列级的操作权限。host权限表配合db权限表对给定主机上数据库级操作权限作更细致的控制。这个权限表不受GRANT和REVOKE语句的影响。
5、MySQL由哪些部分组成
1Server
连接器管理连接、权限验证
分析器词法分析语法分析
优化器执行计划生成索引的选择
执行器操作存储引擎返回执行结果
2存储引擎
存储数据提供读写接口。
6、优化数据库的方法
1选取最合适的字段尽可能减少定义阻断宽度尽量NOTNULL。
2使用JOIN连接来代替子查询。
3使用UNION联合来代替手动创建临时表。
4事务处理。
5锁定表优化事务处理。
6使用外键优化锁定表。
7建立索引。
8优化查询语句。
优化查询过程中的数据访问
访问数据太多导致查询性能下降确定应用程序是否在检索大量超过需要的数据可能是太多行或列确认MySQL服务器是否在分析大量不必要的数据行避免犯如下SQL语句错误查询不需要的数据。解决办法使用limit解决多表关联返回全部列。解决办法指定列名总是返回全部列。解决办法避免使用SELECT *重复查询相同的数据。解决办法可以缓存数据下次直接读取缓存是否在扫描额外的记录。解决办法使用explain进行分析如果发现查询需要扫描大量的数据但只返回少数的行可以通过如下技巧去优化使用索引覆盖扫描把所有的列都放到索引中这样存储引擎不需要回表获取对应行就可以返回结果。改变数据库和表的结构修改数据表范式重写SQL语句让优化器可以以更优的方式执行查询。
优化长难的查询语句
一个复杂查询还是多个简单查询MySQL内部每秒能扫描内存中上百万行数据相比之下响应数据给客户端就要慢得多使用尽可能小的查询是好的但是有时将一个大的查询分解为多个小的查询是很有必要的。切分查询将一个大的查询分为多个小的相同的查询一次性删除1000万的数据要比一次删除1万暂停一会的方案更加损耗服务器开销。分解关联查询让缓存的效率更高。执行单个查询可以减少锁的竞争。在应用层做关联更容易对数据库进行拆分。查询效率会有大幅提升。较少冗余记录的查询。
优化特定类型的查询语句
count()会忽略所有的列直接统计所有列数不要使用count(列名)MyISAM中没有任何where条件的count(*)非常快。当有where条件时MyISAM的count统计不一定比其它引擎快。可以使用explain查询近似值用近似值替代count(*)增加汇总表使用缓存
优化关联查询
确定ON或者USING子句中是否有索引。确保GROUP BY和ORDER BY只有一个表中的列这样MySQL才有可能使用索引。
优化子查询
用关联查询替代
优化GROUP BY和DISTINCT
这两种查询据可以使用索引来优化是最有效的优化方法关联查询中使用标识列分组的效率更高如果不需要ORDER BY进行GROUP BY时加ORDER BY NULLMySQL不会再进行文件排序。WITH ROLLUP超级聚合可以挪到应用程序处理
优化LIMIT分页
LIMIT偏移量大的时候查询效率较低可以记录上次查询的最大ID下次查询时直接根据该ID来查询
优化UNION查询
UNION ALL的效率高于UNION
7、解释一下交叉连接、内连接、外连接
1交叉连接笛卡尔积不使用任何条件直接将一个表的所有记录和另一个表中的所有记录一一匹配。
2内连接只有条件的交叉连接根据某个条件筛选出符合的记录。
3外连接不仅包含符合连接条件的行而且还会包括左表、右表或两个表中的所有数据行。
六种关联查询
交叉连接CROSS JOIN内连接INNER JOIN外连接LEFT JOIN/RIGHT JOIN联合查询UNION与UNION ALL全连接FULL JOIN
外连接LEFT JOIN/RIGHT JOIN
左外连接LEFT OUTER JOIN, 以左表为主先查询出左表按照ON后的关联条件匹配右表没有匹配到的用NULL填充可以简写成LEFT JOIN 右外连接RIGHT OUTER JOIN, 以右表为主先查询出右表按照ON后的关联条件匹配左表没有匹配到的用NULL填充可以简写成RIGHT JOIN
联合查询UNION与UNION ALL
就是把多个结果集集中在一起UNION前的结果为基准需要注意的是联合查询的列数要相等相同的记录行会合并如果使用UNION ALL不会合并重复的记录行效率 UNION 高于 UNION ALL
全连接FULL JOIN
MySQL不支持全连接可以使用LEFT JOIN 和UNION和RIGHT JOIN联合使用
8、为什么要使用NOTNULL
Null值会占用更多的字节并且会在程序中造成很多与预期不符的结果。
9、什么是索引
是一种数据结构可以帮助我们快速的进行数据的查找。
数据库索引是数据库管理系统中一个排序的数据结构以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B树。
更通俗的说索引就相当于目录。为了方便查找书中的内容通过对内容建立索引形成目录。
索引是一个文件它是要占据物理空间的。
优点1提高数据检索的效率降低数据库的IO成本。
2通过索引列对数据进行排序降低数据排序的成本降低CPU的消耗。
缺点1降低更新表的速度。
2索引也是一张表该表保存了主键与索引字段并且指向实体表的记录所以索引表也需要占用空间。
(3)创建索引和维护索引需要消耗时间并且随着数据了的增加所消耗的时间也会增加。
索引有哪几种类型
主键索引: 数据列不允许重复不允许为NULL一个表只能有一个主键。
唯一索引: 数据列不允许重复允许为NULL值一个表允许多个列创建唯一索引。
普通索引: 基本的索引类型没有唯一性的限制允许为NULL值。
全文索引 是目前搜索引擎使用的一种关键技术。
索引的基本原理
把创建了索引的列的内容进行排序对排序结果生成倒排表在倒排表内容上拼上数据地址链在查询的时候先拿到倒排表内容再取出数据地址链从而拿到具体数据
索引设计的原则
适合索引的列是出现在where子句中的列或者连接子句中指定的列基数较小的类索引效果较差没有必要在此列建立索引使用短索引如果对长字符串列进行索引应该指定一个前缀长度这样能够节省大量索引空间不要过度索引。索引需要额外的磁盘空间并降低写操作的性能。在修改表内容的时候索引会进行更新甚至重构索引列越多这个时间就会越长。所以只保持需要的索引有利于查询即可。
创建索引的原则重中之重
索引虽好但也不是无限制的使用最好符合一下几个原则
1 最左前缀匹配原则组合索引非常重要的原则mysql会一直向右匹配直到遇到范围查询(、、between、like)就停止匹配比如a 1 and b 2 and c 3 and d 4 如果建立(a,b,c,d)顺序的索引d是用不到索引的如果建立(a,b,d,c)的索引则都可以用到a,b,d的顺序可以任意调整。
2较频繁作为查询条件的字段才去创建索引
3更新频繁字段不适合创建索引
4若是不能有效区分数据的列不适合做索引列(如性别男女未知最多也就三种区分度实在太低)
5尽量的扩展索引不要新建索引。比如表中已经有a的索引现在要加(a,b)的索引那么只需要修改原来的索引即可。
6定义有外键的数据列一定要建立索引。
7对于那些查询中很少涉及的列重复值比较多的列不要建立索引。
8对于定义为text、image和bit的数据类型的列不要建立索引。
使用索引查询一定能提高查询的性能吗为什么
通常通过索引查询数据比全表扫描要快。但是我们也必须注意到它的代价。
索引需要空间来存储也需要定期维护 每当有记录在表中增减或索引列被修改时索引本身也会被修改。 这意味着每条记录的INSERTDELETEUPDATE将为此多付出45 次的磁盘I/O。 因为索引需要额外的存储空间和处理那些不必要的索引反而会使查询反应时间变慢。使用索引查询不一定能提高查询性能索引范围查询(INDEX RANGE SCAN)适用于两种情况:基于一个范围的检索一般查询返回结果集小于表中记录数的30%基于非唯一性索引的检索
10、什么是事务
事务是一个不可分割的数据库操作序列也是数据库并发控制的基本单位其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态。事务是逻辑上的一组操作要么都执行要么都不执行。
MySQL 事务隔离级别
未提交读 - 读到其它事务未提交的数据最新的版本 错误现象有脏读、不可重复读、幻读现象 提交读RC - 读到其它事务已提交的数据最新已提交的版本 错误现象有不可重复读、幻读现象使用场景希望看到最新的有效值 可重复读RR - 在事务范围内多次读能够保证一致性快照建立时最新已提交版本 错误现象有幻读现象可以用加锁避免使用场景事务内要求更强的一致性但看到的未必是最新的有效值 串行读 - 在事务范围内仅有读读可以并发读写或写写会阻塞其它事务用这种办法保证更强的一致性 错误现象无
11、ACID事务的特性 原子性事务是最小的执行单位不允许分割。事务的原子性确保动作要么全部完成要么完全不起作用
一致性 执行事务前后数据保持一致多个事务对同一个数据读取的结果是相同的
隔离性并发访问数据库时一个用户的事务不被其他事务所干扰各并发事务之间数据库是独立的
持久性一个事务被提交之后。它对数据库中数据的改变是持久的即使数据库发生故障也不应该对其有任何影响。
12、并发事务带来了哪些问题
1脏读一个事务对数据进行了修改还未提交到数据库另一个事务使用了未修改的数据依据这个脏数据所做的操作可能是不正确的。
2丢失修改两个事务同时访问并修改同一个数据那么第一个事务修改的结果就会被丢失。
3不可重复读在一个事务内多次读取同一数据。在这个事务结束之前另一个事务进修改了数据那么第一个事务两次读取的数据就会不一样了。
4幻读发生在一个事务读取了几行数据接着另一个并发事务插入了一些数据在随后的查询中第一个事务就会发现多了一些原本不存在的数据。
13、MySQL的四种隔离级别 1读未提交最低的隔离级别允许读取尚未提交的数据变更可能会导致脏读、幻读或不可重复读。
2读已提交允许读取并发事务已经提交的数据可以阻止脏读但是幻读或不可重复读仍有可能发生。
3可重复读对同一字段的多次读取结果都是一致的除非数据是被本身事务自己所修改可以阻止脏读和不可重复读但幻读仍有可能发生。
4可串行化最高的隔离级别完全服从ACID的隔离级别。所有的事务依次逐个执行这样事务之间就完全不可能产生干扰也就是说该级别可以防止脏读、不可重复读以及幻读。
隔离级别与锁的关系 在Read Uncommitted级别下读取数据不需要加共享锁这样就不会跟被修改的数据上的排他锁冲突 在Read Committed级别下读操作需要加共享锁但是在语句执行完以后释放共享锁 在Repeatable Read级别下读操作需要加共享锁但是在事务提交之前并不释放共享锁也就是必须等待事务执行完毕以后才释放共享锁。 SERIALIZABLE 是限制性最强的隔离级别因为该级别锁定整个范围的键并一直持有锁直到事务完成。 14、MySQL存储引擎MyISAM与InnoDB区别
存储引擎Storage engineMySQL中的数据、索引以及其他对象是如何存储的是一套文件系统的实现。
常用的存储引擎有以下
Innodb引擎Innodb引擎提供了对数据库ACID事务的支持。并且还提供了行级锁和外键的约束。它的设计的目标就是处理大数据容量的数据库系统。MyIASM引擎(原本Mysql的默认引擎)不提供事务的支持也不支持行级锁和外键。MEMORY引擎所有的数据都在内存中数据的处理速度快但是安全性不高。
MyISAM索引与InnoDB索引的区别
InnoDB索引是聚簇索引MyISAM索引是非聚簇索引。InnoDB的主键索引的叶子节点存储着行数据因此主键索引非常高效。MyISAM索引的叶子节点存储的是行数据地址需要再寻址一次才能得到数据。InnoDB非主键索引的叶子节点存储的是主键和其他带索引的列数据因此查询时做到覆盖索引会非常高效。
MyISAM与InnoDB区别 InnoDB支持事务MyISAM不支持事务InnoDB支持外键MyISAM不支持外键InnoDB 支持 MVCC(多版本并发控制)MyISAM 不支持select count(*) from table时MyISAM更快因为它有一个变量保存了整个表的总行数可以直接读取InnoDB就需要全表扫描。Innodb不支持全文索引而MyISAM支持全文索引5.7以后的InnoDB也支持全文索引InnoDB支持表、行级锁而MyISAM支持表级锁。InnoDB表必须有主键而MyISAM可以没有主键Innodb表需要更多的内存和存储而MyISAM可被压缩存储空间较小。Innodb按主键大小有序插入MyISAM记录插入顺序是按记录插入顺序保存。InnoDB 存储引擎提供了具有提交、回滚、崩溃恢复能力的事务安全与 MyISAM 比 InnoDB 写的效率差一些并且会占用更多的磁盘空间以保留数据和索引 InnoDB引擎的4大特性
插入缓冲insert buffer)二次写(double write)自适应哈希索引(ahi)预读(read ahead)
15、百万级别或以上的数据如何删除
所以我们想要删除百万数据的时候可以先删除索引此时大概耗时三分多钟然后删除其中无用数据此过程需要不到两分钟删除完成后重新创建索引(此时数据较少了)创建索引也非常快约十分钟左右。与之前的直接删除绝对是要快速很多更别说万一删除中断,一切删除会回滚。那更是坑了。
16、数据库为什么使用B树而不是B树
B树只适合随机检索B树空间利用率更高可减少I/O次数磁盘读写代价更低。B树的查询效率更加稳定。B树在提高了磁盘IO性能的同时并没有解决元素遍历的效率低下的问题。增删文件节点时效率更高。
17、对MySQL的锁了解吗
当数据库有并发事务的时候可能会产生数据的不一致这时候需要一些机制来保证访问的次序锁机制就是这样的一个机制。
什么是死锁怎么解决 死锁是指两个或多个事务在同一资源上相互占用并请求锁定对方的资源从而导致恶性循环的现象。
常见的解决死锁的方法
1、如果不同程序会并发存取多个表尽量约定以相同的顺序访问表可以大大降低死锁机会。
2、在同一个事务中尽可能做到一次锁定所需要的所有资源减少死锁产生概率
3、对于非常容易产生死锁的业务部分可以尝试使用升级锁定颗粒度通过表级锁定来减少死锁产生的概率
如果业务处理不好可以用分布式事务锁或者使用乐观锁
数据库的乐观锁和悲观锁是什么怎么实现的
数据库管理系统DBMS中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制乐观锁和悲观并发控制悲观锁是并发控制主要采用的技术手段。
悲观锁假定会发生并发冲突屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来直到提交事务。实现方式使用数据库中的锁机制
乐观锁假设不会发生并发冲突只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来通过version的方式来进行锁定。实现方式乐一般会使用版本号机制或CAS算法实现。
18、为什么要使用视图什么是视图
为了提高复杂SQL语句的复用性和表操作的安全性。
一种虚拟表在物理上是不存在的其内容与真实的表相似包含一系列带有名称的列和行数据。
视图并不在数据库中以储存的数据值形式存在。行和列数据来自定义视图的查询所引用基本表并且在具体引用视图时动态生成。
19、视图有哪些特点
视图的列可以来自不同的表是表的抽象和在逻辑意义上建立的新关系。视图是由基本表(实表)产生的表(虚表)。视图的建立和删除不影响基本表。对视图内容的更新(添加删除和修改)直接影响基本表。当视图来自多个基本表时不允许添加和删除数据。
20、视图的使用场景有哪些
重用SQL语句简化复杂的SQL操作。在编写查询后可以方便的重用它而不必知道它的基本查询细节使用表的组成部分而不是整个表保护数据。可以给用户授予表的特定部分的访问权限而不是整个表的访问权限更改数据格式和表示。视图可返回与底层表的表示和格式不同的数据。
21、视图的优点
查询简单化。视图能简化用户的操作数据安全性。视图使用户能以多种角度看待同一数据能够对机密数据提供安全保护逻辑数据独立性。视图对重构数据库提供了一定程度的逻辑独立性
22、视图的缺点 性能。数据库必须把视图的查询转化成对基本表的查询如果这个视图是由一个复杂的多表查询所定义那么即使是视图的一个简单查询数据库也把它变成一个复杂的结合体需要花费一定的时间。 修改限制。当用户试图修改视图的某些行时数据库必须把它转化为对基本表的某些行的修改。事实上当从视图中插入或者删除时情况也是这样。对于简单视图来说这是很方便的但是对于比较复杂的视图可能是不可修改的 这些视图有如下特征1.有UNIQUE等集合操作符的视图。2.有GROUP BY子句的视图。3.有诸如AVG\SUM\MAX等聚合函数的视图。 4.使用DISTINCT关键字的视图。5.连接表的视图其中有些例外
23、存储过程与函数
什么是存储过程有哪些优缺点 存储过程是一个预编译的SQL语句优点是允许模块化的设计就是说只需要创建一次以后在该程序中就可以调用多次。如果某次操作需要执行多次SQL使用存储过程比单纯SQL语句执行要快。
优点
1存储过程是预编译过的执行效率高。
2存储过程的代码直接存放于数据库中通过存储过程名直接调用减少网络通讯。
3安全性高执行存储过程需要有一定权限的用户。
4存储过程可以重复使用减少数据库开发人员的工作量。
缺点
1调试麻烦但是用 PL/SQL Developer 调试很方便弥补这个缺点。
2移植问题数据库端代码当然是与数据库相关的。但是如果是做工程型项目基本不存在移植问题。
3重新编译问题因为后端代码是运行前编译的如果带有引用关系的对象发生改变时受影响的存储过程、包将需要重新编译不过也可以设置成运行时刻自动编译。
4如果在一个程序系统中大量的使用存储过程到程序交付使用的时候随着用户需求的增加会导致数据结构的变化接着就是系统的相关问题了最后如果用户想维护该系统可以说是很难很难、而且代价是空前的维护起来更麻烦。
24、什么是触发器触发器的使用场景有哪些
触发器是用户定义在关系表上的一类由事件驱动的特殊的存储过程。触发器是指一段代码当触发某个事件时自动执行这些代码。
使用场景
可以通过数据库中的相关表实现级联更改。实时监控某张表中的某个字段的更改而需要做出相应的处理。例如可以生成某些业务的编号。注意不要滥用否则会造成数据库及应用程序的维护困难。大家需要牢记以上基础知识点重点是理解数据类型CHAR和VARCHAR的差异表存储引擎InnoDB和MyISAM的区别。
25、超键、候选键、主键、外键分别是什么
超键在关系中能唯一标识元组的属性集称为关系模式的超键。一个属性可以为作为一个超键多个属性组合在一起也可以作为一个超键。超键包含候选键和主键。候选键是最小超键即没有冗余元素的超键。主键数据库表中对储存数据对象予以唯一和完整标识的数据列或属性的组合。一个数据列只能有一个主键且主键的取值不能缺失即不能为空值Null。外键在一个表中存在的另一个表的主键称此表的外键。
26、什么是子查询
条件一条SQL语句的查询结果做为另一条查询语句的条件或查询结果嵌套多条SQL语句嵌套使用内部的SQL查询语句称为子查询。
27、mysql中 in 和 exists 区别
mysql中的in语句是把外表和内表作hash 连接而exists语句是对外表作loop循环每次loop循环再对内表进行查询。一直大家都认为exists比in语句的效率要高这种说法其实是不准确的。这个是要区分环境的。
28、大表数据查询怎么优化
优化shema、sql语句索引第二加缓存memcached, redis主从复制读写分离垂直拆分根据你模块的耦合度将一个大的系统分为多个小的系统也就是分布式系统水平切分针对数据量大的表这一步最麻烦最能考验技术水平要选择一个合理的sharding key, 为了有好的查询效率表结构也要改动做一定的冗余应用也要改sql中尽量带sharding key将数据定位到限定的表上去查而不是扫描全部的表
29、超大分页怎么处理
数据库层面,这也是我们主要集中关注的(虽然收效没那么大),类似于select * from table where age 20 limit 1000000,10这种查询其实也是有可以优化的余地的. 这条语句需要load1000000数据然后基本上全部丢弃,只取10条当然比较慢. 当时我们可以修改为select * from table where id in (select id from table where age 20 limit 1000000,10).这样虽然也load了一百万的数据,但是由于索引覆盖,要查询的所有字段都在索引中,所以速度会很快. 同时如果ID连续的好,我们还可以select * from table where id 1000000 limit 10,效率也是不错的,优化的可能性有许多种,但是核心思想都一样,就是减少load的数据.从需求的角度减少这种请求…主要是不做类似的需求(直接跳转到几百万页之后的具体某一页.只允许逐页查看或者按照给定的路线走,这样可预测,可缓存)以及防止ID泄漏且连续被人恶意攻击.
30、关心过业务系统里面的sql耗时吗统计过慢查询吗对慢查询都怎么优化过
首先分析语句看看是否load了额外的数据可能是查询了多余的行并且抛弃掉了可能是加载了许多结果中并不需要的列对语句进行分析以及重写。分析语句的执行计划然后获得其使用索引的情况之后修改语句或者修改索引使得语句可以尽可能的命中索引。 如果对语句的优化已经无法进行可以考虑表中的数据量是否太大如果是的话可以进行横向或者纵向的分表。
31、CHAR 和VARCHAR 的区别 CHAR 和 VARCHAR 类型在存储和检索方面有所不同CHAR 列长度固定为创建表时声明的长度 长度值范围是 1 到 255 当 CHAR 值被存储时 它们被用空格填充到特定长度 检索 CHAR 值时需删除尾随空格。 32、数据库索引的原理为什么要用B树为什么不用二叉树 为什么不是一般二叉树 如果二叉树特殊化为一个链表相当于全表扫描。平衡二叉树相比于二叉查找树来说查找效率更稳定总体的查找速度也更快。 为什么不是平衡二叉树呢 我们知道在内存比在磁盘的数据查询效率快得多。如果树这种数据结构作为索引那我们每查找一次数据就需要从磁盘中读取一个节点也就是我们说的一个磁盘块但是平衡二叉树可是每个节点只存储一个键值和数据的如果是B树可以存储更多的节点数据树的高度也会降低因此读取磁盘的次数就降下来啦查询效率就快啦。 那为什么不是B树而是B树呢 B树非叶子节点上是不存储数据的仅存储键值而B树节点中不仅存储键值也会存储数据。innodb中页的默认大小是16KB如果不存储数据那么就会存储更多的键值相应的树的阶数节点的子节点树就会更大树就会更矮更胖如此一来我们查找数据进行磁盘的IO次数有会再次减少数据查询的效率也会更快。B树索引的所有数据均存储在叶子节点而且数据是按照顺序排列的链表连着的。那么B树使得范围查找排序查找分组查找以及去重查找变得异常简单。 33、数据库自增主键可能遇到什么问题
使用自增主键对数据库做分库分表可能出现诸如主键重复等的问题。解决方案的话简单点的话可以考虑使用UUID解决复杂的可以考虑前面提到的分布式主键方案自增主键会产生表锁从而引发问题自增主键可能用完问题。
34、Blob和text有什么区别
Blob用于存储二进制数据而Text用于存储大字符串。Blob值被视为二进制字符串字节字符串,它们没有字符集并且排序和比较基于列值中的字节的数值。text值被视为非二进制字符串字符字符串。它们有一个字符集并根据字符集的排序规则对值进行排序和比较
35、count(1)、count(*) 与 count(列名) 的区别 count(*)包括了所有的列相当于行数在统计结果的时候不会忽略列值为NULLcount(1)包括了忽略所有列用1代表代码行在统计结果的时候不会忽略列值为NULLcount(列名)只包括列名那一列在统计结果的时候会忽略列值为空这里的空不是指空字符串或者0而是表示null的计数即某个字段值为NULL时不统计。 36、查询语句执行流程 连接器负责建立连接、检查权限、连接超时时间由 wait_timeout 控制默认 8 小时查询缓存会将 SQL 和查询结果以键值对方式进行缓存修改操作会以表单位导致缓存失效分析器词法、语法分析优化器决定用哪个索引决定表的连接顺序等执行器根据存储引擎类型调用存储引擎接口存储引擎数据的读写接口索引、表都在此层实现
37、MySQL锁
1、全局锁
用作全量备份时保证表与表之间的数据一致性
如果不加任何包含数据备份时就可能产生不一致的情况如下图所示 使用全局读锁锁定所有数据库的所有表。这时会阻塞其它所有 DML 以及 DDL 操作这样可以避免备份过程中的数据不一致。接下来可以执行备份最后用 unlock tables 来解锁
2、表级锁
1、表锁 语法加锁 lock tables 表名 read/write解锁 unlock tables缺点粒度较粗在 InnoDB 引擎很少使用 2、元数据锁 即 metadata-lockMDL主要是为了避免 DML 与 DDL 冲突DML 的元数据锁之间不互斥 加元数据锁的几种情况 lock tables read/write类型为 SHARED_READ_ONLY 和 SHARED_NO_READ_WRITEalter table类型为 EXCLUSIVE与其它 MDL 都互斥selectselect … lock in share mode类型为 SHARED_READinsertupdatedeleteselect for update类型为 SHARED_WRITE 查看元数据锁适用于 MySQL 8.0 以上版本 select object_type,object_schema,object_name,lock_type,lock_duration from performance_schema.metadata_locks; 3、行级锁
种类 行锁 – 在 RC 下锁住的是行防止其他事务对此行 update 或 delete间隙锁 – 在 RR 下锁住的是间隙防止其他事务在这个间隙 insert 产生幻读临键锁 – 在 RR 下锁住的是前面间隙行特定条件下可优化为行锁 查看行级锁 select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_locks where object_name表名; 注意 它们锁定的其实都是索引上的行与间隙根据索引的有序性来确定间隙 38、什么是最左前缀原则什么是最左匹配原则
顾名思义就是最左优先在创建多列索引时要根据业务需求where子句中使用最频繁的一列放在最左边。最左前缀匹配原则非常重要的原则mysql会一直向右匹配直到遇到范围查询(、、between、like)就停止匹配比如a 1 and b 2 and c 3 and d 4 如果建立(a,b,c,d)顺序的索引d是用不到索引的如果建立(a,b,d,c)的索引则都可以用到a,b,d的顺序可以任意调整。和in可以乱序比如a 1 and b 2 and c 3 建立(a,b,c)索引可以任意顺序mysql的查询优化器会帮你优化成索引可以识别的形式
39、什么是聚簇索引何时使用聚簇索引与非聚簇索引
聚簇索引将数据存储与索引放到了一块找到索引也就找到了数据非聚簇索引将数据存储于索引分开结构索引结构的叶子节点指向了数据的对应行myisam通过key_buffer把索引先缓存到内存中当需要访问数据时通过索引访问数据在内存中直接搜索索引然后通过索引找到磁盘相应数据这也就是为什么索引不在key buffer命中时速度慢的原因。
40、联合索引是什么为什么需要注意联合索引中的顺序
MySQL可以使用多个字段同时建立一个索引叫做联合索引。在联合索引中如果想要命中索引需要按照建立索引时的字段顺序挨个使用否则无法命中索引。
具体原因为:
MySQL使用索引时需要索引有序假设现在建立了nameageschool的联合索引那么索引的排序为: 先按照name排序如果name相同则按照age排序如果age的值也相等则按照school进行排序。
当进行查询时此时索引仅仅按照name严格有序因此必须首先使用name字段进行等值查询之后对于匹配到的列而言其按照age字段严格有序此时可以使用age字段用做索引查找以此类推。因此在建立联合索引的时候应该注意索引列的顺序一般情况下将查询需求频繁或者字段选择性高的列放在前面。此外可以根据特例的查询或者表结构进行单独的调整。
41、SQL语句主要分为哪几类 数据定义语言DDLData Ddefinition LanguageCREATEDROPALTER 主要为以上操作 即对逻辑结构等有操作的其中包括表结构视图和索引。 数据查询语言DQLData Query LanguageSELECT 这个较为好理解 即查询操作以select关键字。各种简单查询连接查询等 都属于DQL。 数据操纵语言DMLData Manipulation LanguageINSERTUPDATEDELETE 主要为以上操作 即对数据进行操作的对应上面所说的查询操作 DQL与DML共同构建了多数初级程序员常用的增删改查操作。而查询是较为特殊的一种 被划分到DQL中。 数据控制功能DCLData Control LanguageGRANTREVOKECOMMITROLLBACK 主要为以上操作 即对数据库安全性完整性等有操作的可以简单的理解为权限控制等。 42、超键、候选键、主键、外键分别是什么
超键在关系中能唯一标识元组的属性集称为关系模式的超键。一个属性可以为作为一超键多个属性组合在一起也可以作为一个超键。超键包含候选键和主键。候选键是最小超键即没有冗余元素的超键。主键数据库表中对储存数据对象予以唯一和完整标识的数据列或属性的组合。一个数据列只能有一个主键且主键的取值不能缺失即不能为空值Null。外键在一个表中存在的另一个表的主键称此表的外键。
43、SQL 约束有哪几种 NOT NULL: 用于控制字段的内容一定不能为空NULL。UNIQUE: 控件字段内容不能重复一个表允许有多个 Unique 约束。PRIMARY KEY: 也是用于控件字段内容不能重复但它在一个表只允许出现一个。FOREIGN KEY: 用于预防破坏表之间连接的动作也能防止非法数据插入外键列因为它必须是它指向的那个表中的值之一。CHECK: 用于控制字段的值范围。 44、varchar(50)中50的涵义 最多存放50个字符varchar(50)和(200)存储hello所占空间一样但后者在排序时会消耗更多内存因为order by col采用fixed_length计算col长度(memory引擎也一样)。在早期 MySQL 版本中 50 代表字节数现在代表字符数。 45、int(20)中20的涵义 是指显示字符的长度。20表示最大显示宽度为20但仍占4字节存储存储范围不变 不影响内部存储只是影响带 zerofill 定义的 int 时前面补多少个 0易于报表展示 46、为什么要尽量设定一个主键 主键是数据库确保数据行在整张表唯一性的保障即使业务上本张表没有主键也建议添加一个自增长的ID列作为主键。设定了主键之后在后续的删改查的时候可能更加快速以及确保操作数据范围安全。 47、MySQL的复制原理以及流程 主从复制将主数据库中的DDL和DML操作通过二进制日志BINLOG传输到从数据库上然后将这些日志重新执行重做从而使得从数据库的数据与主数据库保持一致。 48、MySQL主从复制的作用 主数据库出现问题可以切换到从数据库。可以进行数据库层面的读写分离。可以在从数据库上进行日常备份。 49、MySQL主从复制工作原理 在主库上把数据更高记录到二进制日志从库将主库的日志复制到自己的中继日志从库读取中继日志的事件将其重放到从库数据中 50、什么是死锁怎么解决 死锁是指两个或多个事务在同一资源上相互占用并请求锁定对方的资源从而导致恶性循环的现象。 常见的解决死锁的方法 1、如果不同程序会并发存取多个表尽量约定以相同的顺序访问表可以大大降低死锁机会。 2、在同一个事务中尽可能做到一次锁定所需要的所有资源减少死锁产生概率 3、对于非常容易产生死锁的业务部分可以尝试使用升级锁定颗粒度通过表级锁定来减少死锁产生的概率 如果业务处理不好可以用分布式事务锁或者使用乐观锁 51、数据库的乐观锁和悲观锁是什么怎么实现的
数据库管理系统DBMS中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制乐观锁和悲观并发控制悲观锁是并发控制主要采用的技术手段。
悲观锁假定会发生并发冲突屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来直到提交事务。实现方式使用数据库中的锁机制
乐观锁假设不会发生并发冲突只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来通过version的方式来进行锁定。实现方式乐观锁一般会使用版本号机制或CAS算法实现。
两种锁的使用场景
从上面对两种锁的介绍我们知道两种锁各有优缺点不可认为一种好于另一种像乐观锁适用于写比较少的情况下多读场景即冲突真的很少发生的时候这样可以省去了锁的开销加大了系统的整个吞吐量。
但如果是多写的情况一般会经常产生冲突这就会导致上层应用会不断的进行retry这样反倒是降低了性能所以一般多写的场景下用悲观锁就比较合适。
51、drop、delete与truncate的区别
三者都是表示删除但是三者都有一些差别 因此在不再需要一张表的时候用drop在想删除部分数据行时候用 delete在保留表而删除所有数据的时候用truncate。
52、UNION与UNIONALL的区别 如果使用UNION ALL不会合并重复的记录行 效率 UNION 高于 UNION ALL 53、按照锁的粒度分数据库锁有哪些 在关系型数据库中可以按照锁的粒度把数据库锁分为行级锁(INNODB引擎)、表级锁(MYISAM引擎)和页级锁(BDB引擎 )。 MyISAM和InnoDB存储引擎使用的锁 MyISAM采用表级锁(table-level locking)。 InnoDB支持行级锁(row-level locking)和表级锁默认为行级锁 行级锁表级锁和页级锁对比
行级锁 行级锁是Mysql中锁定粒度最细的一种锁表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小但加锁的开销也最大。行级锁分为共享锁 和 排他锁。 特点开销大加锁慢会出现死锁锁定粒度最小发生锁冲突的概率最低并发度也最高。 表级锁 表级锁是MySQL中锁定粒度最大的一种锁表示对当前操作的整张表加锁它实现简单资源消耗较少被大部分MySQL引擎支持。最常使用的MYISAM与INNODB都支持表级锁定。表级锁定分为表共享读锁共享锁与表独占写锁排他锁。 特点开销小加锁快不会出现死锁锁定粒度大发出锁冲突的概率最高并发度最低。 页级锁 页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快但冲突多行级冲突少但速度慢。所以取了折衷的页级一次锁定相邻的一组记录。 特点开销和加锁时间界于表锁和行锁之间会出现死锁锁定粒度界于表锁和行锁之间并发度一般
54、数据库中有六种触发器 Before InsertAfter InsertBefore UpdateAfter UpdateBefore DeleteAfter Delete 55、Hash索引和B树索引有什么区别或者说优劣呢?
首先要知道Hash索引和B树索引的底层实现原理:
hash索引底层就是hash表,进行查找时,调用一次hash函数就可以获取到相应的键值,之后进行回表查询获得实际数据.B树底层实现是多路平衡查找树.对于每一次的查询都是从根节点出发,查找到叶子节点方可以获得所查键值,然后根据查询判断是否需要回表查询数据.
那么可以看出他们有以下的不同:hash索引进行等值查询更快(一般情况下),但是却无法进行范围查询. 因为在hash索引中经过hash函数建立索引之后,索引的顺序与原顺序无法保持一致,不能支持范围查询.而B树的的所有节点皆遵循(左节点小于父节点,右节点大于父节点,多叉树也类似),天然支持范围. hash索引不支持使用索引进行排序,原理同上. hash索引不支持模糊查询以及多列索引的最左前缀匹配.原理也是因为hash函数的不可预测.AAAA和AAAAB的索引没有相关性. hash索引任何时候都避免不了回表查询数据,而B树在符合某些条件(聚簇索引,覆盖索引等)的时候可以只通过索引完成查询. hash索引虽然在等值查询上较快,但是不稳定.性能不可预测,当某个键值存在大量重复的时候,发生hash碰撞,此时效率可能极差.而B树的查询效率比较稳定,对于所有的查询都是从根节点到叶子节点,且树的高度较低. 因此,在大多数情况下,直接选择B树索引可以获得稳定且较好的查询速度.而不需要使用hash索引.
七、SSM面试题
Spring
1、什么是Spring
Spring 是个java企业级应用的开源开发框架。Spring主要用来开发Java应用但是有些扩展是针对构建J2EE平台的web应用。Spring 框架目标是简化Java企业级应用开发并通过POJO为基础的编程模型促进良好的编程习惯。
2、你们项目中为什么使用Spring框架
轻量Spring 是轻量的基本的版本大约2MB。控制反转Spring通过控制反转实现了松散耦合对象们给出它们的依赖而不是创建或查找依赖的对象们。面向切面的编程(AOP)Spring支持面向切面的编程并且把应用业务逻辑和系统服务分开。容器Spring 包含并管理应用中对象的生命周期和配置。MVC框架Spring的WEB框架是个精心设计的框架是Web框架的一个很好的替代品。事务管理Spring 提供一个持续的事务管理接口可以扩展到上至本地事务下至全局事务异常处理Spring 提供方便的API把具体技术相关的异常比如由JDBCHibernate or JDO抛出的转化为一致的unchecked 异常。
3、Autowired和Resource关键字的区别
Resource和Autowired都是做bean的注入时使用其实Resource并不是Spring的注解它的包是javax.annotation.Resource需要导入但是Spring支持该注解的注入。
共同点两者都可以写在字段和setter方法上。两者如果都写在字段上那么就不需要再写setter方法。不同点1Autowired为Spring提供的注解需要导入包org.springframework.beans.factory.annotation.Autowired;只按照byType注入。Autowired注解是按照类型byType装配依赖对象默认情况下它要求依赖对象必须存在如果允许null值可以设置它的required属性为false。如果我们想使用按照名称byName来装配可以结合Qualifier注解一起使用。2Resource默认按照ByName自动注入由J2EE提供需要导入包javax.annotation.Resource。Resource有两个重要的属性name和type而Spring将Resource注解的name属性解析为bean的名字而type属性则解析为bean的类型。所以如果使用name属性则使用byName的自动注入策略而使用type属性时则使用byType自动注入策略。如果既不制定name也不制定type属性这时将通过反射机制使用byName自动注入策略。
4、依赖注入的方式有几种各是什么?
构造器注入 将被依赖对象通过构造函数的参数注入给依赖对象并且在初始化对象的时候注入。优点 对象初始化完成后便可获得可使用的对象。缺点 当需要注入的对象很多时构造器参数列表将会很长 不够灵活。若有多种注入方式每种方式只需注入指定几个依赖那么就需要提供多个重载的构造函数麻烦。setter方法注入 IoC Service Provider通过调用成员变量提供的setter函数将被依赖对象注入给依赖类。优点 灵活。可以选择性地注入需要的对象。缺点 依赖对象初始化完成后由于尚未注入被依赖对象因此还不能使用。通过接口
5、说说你对Spring的IOC是怎么理解的
IOC就是控制反转是指创建对象的控制权的转移。以前创建对象的主动权和时机是由自己把控的而现在这种权力转移到Spring容器中并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系。对象与对象之间松散耦合也利于功能的复用。DI依赖注入和控制反转是同一个概念的不同角度的描述即 应用程序在运行时依赖IoC容器来动态注入对象需要的外部资源。最直观的表达就是IOC让对象的创建不用去new了可以由spring自动生产使用java的反射机制根据配置文件在运行时动态的去创建对象以及管理对象并调用对象的方法的。Spring的IOC有三种注入方式 构造器注入、setter方法注入、根据注解注入。IoC让相互协作的组件保持松散的耦合而AOP编程允许你把遍布于应用各层的功能分离出来形成可重用的功能组件。
6、谈谈你对Spring的AOP理解
AOPAspect-Oriented Programming面向切面编程能够将那些与业务无关却为业务模块所共同调用的逻辑或责任例如事务处理、日志管理、权限控制等封装起来便于减少系统的重复代码降低模块间的耦合度并有利于未来的可扩展性和可维护性。Spring AOP是基于动态代理的如果要代理的对象实现了某个接口那么Spring AOP就会使用JDK动态代理去创建代理对象而对于没有实现接口的对象就无法使用JDK动态代理转而使用CGlib动态代理生成一个被代理对象的子类来作为代理。当然也可以使用AspectJSpring AOP中已经集成了AspectJAspectJ应该算得上是Java生态系统中最完整的AOP框架了。使用AOP之后我们可以把一些通用功能抽象出来在需要用到的地方直接使用即可这样可以大大简化代码量。我们需要增加新功能也方便提高了系统的扩展性。日志功能、事务管理和权限管理等场景都用到了AOP。
7、Spring AOP和AspectJ AOP有什么区别
Spring AOP是属于运行时增强而AspectJ是编译时增强。Spring AOP基于代理Proxying而AspectJ基于字节码操作Bytecode Manipulation。Spring AOP已经集成了AspectJAspectJ应该算得上是Java生态系统中最完整的AOP框架了。AspectJ相比于Spring AOP功能更加强大但是Spring AOP相对来说更简单。如果我们的切面比较少那么两者性能差异不大。但是当切面太多的话最好选择AspectJ它比SpringAOP快很多。
8、在Spring AOP 中关注点和横切关注的区别是什么
关注点是应用中一个模块的行为一个关注点可能会被定义成一个我们想实现的一个功能。 横切关注点是一个关注点此关注点是整个应用都会使用的功能并影响整个应用比如日志安全和数据传输几乎应用的每个模块都需要的功能。因此这些都属于横切关注点。那什么是连接点呢连接点代表一个应用程序的某个位置在这个位置我们可以插入一个AOP切面它实际上是个应用程序执行Spring AOP的位置。切入点是什么切入点是一个或一组连接点通知将在这些位置执行。可以通过表达式或匹配的方式指明切入点。
9、什么是通知呢有哪些类型呢
通知是个在方法执行前或执行后要做的动作实际上是程序执行时要通过SpringAOP框架触发的代码段。
Spring切面可以应用五种类型的通知
before前置通知在一个方法执行前被调用。after: 在方法执行之后调用的通知无论方法执行是否成功。after-returning: 仅当方法成功完成后执行的通知。after-throwing: 在方法抛出异常退出时执行的通知。around: 在方法执行之前和之后调用的通知。
10、解释一下spring bean的生命周期
Bean 容器找到配置文件中 Spring Bean 的定义。Bean 容器利用 Java Reflection API 创建一个 Bean 的实例。如果涉及到一些属性值 利用 set()方法设置一些属性值。如果 Bean 实现了 BeanNameAware 接口调用 setBeanName()方法传入 Bean 的名字。如果 Bean 实现了 BeanClassLoaderAware 接口调用 setBeanClassLoader()方法传入 ClassLoader对象的实例。如果 Bean 实现了 BeanFactoryAware 接口调用 setBeanFactory()方法传入 BeanFactory对象的实例。如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象执行postProcessBeforeInitialization() 方法如果 Bean 实现了InitializingBean接口执行afterPropertiesSet()方法。如果 Bean 在配置文件中的定义包含 init-method 属性执行指定的方法。当要销毁 Bean 的时候如果 Bean 实现了 DisposableBean 接口执行 destroy() 方法。当要销毁 Bean 的时候如果 Bean 在配置文件中的定义包含 destroy-method 属性执行指定的方法。
11、解释Spring支持的几种bean的作用域
singleton默认每个容器中只有一个bean的实例单例的模式由BeanFactory自身来维护。prototype每次获取都会创建一个新的 bean 实例。也就是说连续 getBean() 两次得到的是不同的 Bean 实例。request每一次 HTTP 请求都会产生一个新的 bean请求 bean该 bean 仅在当前 HTTP request 内有效。session 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean会话 bean该 bean 仅在当前 HTTP session 内有效。global-session每个 Web 应用在启动时创建一个 Bean应用 Bean该 bean 仅在当前应用启动时间内有效。
12、静态代理和动态代理的区别
静态代理只能代理一种业务如果有多种业务需要编写多个代理类
动态代理通过反射机制动态生成代理类不需要手动编写能够代理多种业务更加灵活。
13、JDK动态代理和CGLIB动态代理的区别
Spring AOP中的动态代理主要有两种方式JDK动态代理和CGLIB动态代理
JDK动态代理只提供接口的代理不支持类的代理。核心InvocationHandler接口和Proxy类InvocationHandler 通过invoke()方法反射来调用目标类中的代码动态地将横切逻辑和业务编织在一起接着Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。如果代理类没有实现 InvocationHandler 接口那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIBCode Generation Library是一个代码生成的类库可以在运行时动态的生成指定类的一个子类对象并覆盖其中特定方法并添加增强代码从而实现AOP。CGLIB是通过继承的方式做的动态代理因此如果某个类被标记为final那么它是无法使用CGLIB做动态代理的。 静态代理与动态代理区别在于生成AOP代理对象的时机不同相对来说AspectJ的静态代理方式具有更好的性能但是AspectJ需要特定的编译器进行处理而Spring AOP则无需特定的编译器处理。 14、Spring框架中都用到了哪些设计模式
工厂设计模式 : Spring 使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。代理设计模式 : Spring AOP 功能的实现。单例设计模式 : Spring 中的 Bean 默认都是单例的。模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类它们就使用到了模板模式。包装器设计模式 : 我们的项目需要连接多个数据库而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。适配器模式 : Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配
15、说说Spring 中 ApplicationContext 和 BeanFactory 的区别
16、Spring 框架中的单例 Bean 是线程安全的么
Spring 框架并没有对单例 Bean 进行任何多线程的封装处理。
关于单例 Bean 的线程安全和并发问题需要开发者自行去搞定。单例的线程安全问题并不是 Spring 应该去关心的。Spring 应该做的是提供根据配置创建单例 Bean 或多例 Bean 的功能。 但实际上大部分的 Spring Bean 并没有可变的状态所以在某种程度上说 Spring 的单例Bean 是线程安全的。如果你的 Bean 有多种状态的话就需要自行保证线程安全。最浅显的解决办法就是将多态 Bean 的作用域Scope由 Singleton 变更为 Prototype。 17、Spring 是怎么解决循环依赖的
循环依赖是指一个或多个Bean实例之间存在直接或间接的依赖关系构成循环调用。通常表现为三种形态。互相依赖也就是A依赖BB依赖A
Spring设计了三级缓存来解决循环依赖问题。
第一级缓存里面存储完整的Bean实例这些实例是可以直接被使用的。第二级缓存里面存储的是实例化以后但是还没有设置属性值的Bean实例也就是Bean里面的依赖注入还没有做。第三级缓存用来存放Bean工厂它主要用来生成原始Bean对象并且放到第二级缓存里面。三级缓存的核心思想就是把Bean的实例化和Bean里面的依赖注入进行分离。采用一级缓存存储完整的Bean实例采用二级缓存来存储不完整的Bean实例通过不完整的Bean实例作为突破口解决循环依赖的问题。至于第三级缓存主要是解决代理对象的循环依赖问题
18、Spring 管理事务的方式有几种
编程式事务 在代码中硬编码(不推荐使用) : 通过 TransactionTemplate或者 TransactionManager 手动管理事务实际应用中很少使用但是对于你理解 Spring 事务管理原理有帮助。声明式事务 在 XML 配置文件中配置或者直接基于注解推荐使用 : 实际是通过 AOP 实现基于Transactional 的全注解方式使用最多
19、Spring 事务中的隔离级别有哪几种?
TransactionDefinition.ISOLATION_DEFAULT :使用后端数据库默认的隔离级别MySQL 默认采用的 REPEATABLE_READ 隔离级别 Oracle 默认采用的 READ_COMMITTED 隔离级别.TransactionDefinition.ISOLATION_READ_UNCOMMITTED :最低的隔离级别使用这个隔离级别很少因为它允许读取尚未提交的数据变更可能会导致脏读、幻读或不可重复读TransactionDefinition.ISOLATION_READ_COMMITTED : 允许读取并发事务已经提交的数据可以阻止脏读但是幻读或不可重复读仍有可能发生TransactionDefinition.ISOLATION_REPEATABLE_READ : 对同一字段的多次读取结果都是一致的除非数据是被本身事务自己所修改可以阻止脏读和不可重复读但幻读仍有可能发生。TransactionDefinition.ISOLATION_SERIALIZABLE : 最高的隔离级别完全服从 ACID 的隔离级别。所有的事务依次逐个执行这样事务之间就完全不可能产生干扰也就是说该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别
SpringMVC
1、SpringMVC的执行流程 用户发送请求给前端控制器前端控制器将请求的URL发送给处理器映射处理器映射将请求里面的handler包装的信息和方法返回给前端控制器前端控制器发送handler给适配器适配器执行handler里的方法适配器执行完毕后返回逻辑视图给前端控制器前端控制器再将逻辑视图发送给视图解析器解析成物理视图返回给前端控制器前端控制器渲染视图发送视图给用户
2、SpringMVC中的拦截器和Servlet中的Filter过滤器的区别
拦截器用于过滤请求只能在SpringMVC中使用效率高
过滤器拦截范围更大
3、什么是Spring MVC简单介绍下你对Spring MVC的理解 首先SpringMVC是是属于SpringFramework生态里面的一个模块它是在Servlet基础上构建并且使用MVC模式设计的一个Web框架主要的目的是简化传统ServletJSP模式下的Web开发方式。其次SpringMVC的整体架构设计对JavaWeb里面的MVC架构模式做了增强和扩展主要有几个方面。把传统MVC框架里面的Controller控制器做了拆分分成了前端控制器DispatcherServlet和后端控制器Controller。把Model模型拆分成业务层Service和数据访问层Repository。在视图层可以支持不同的视图比如Freemark、velocity、JSP等等。所以SpringMVC天生就是为了MVC模式而设计的因此在开发MVC应用的时候会更加方便和灵活。SpringMVC的具体工作流程是浏览器的请求首先会经过SpringMVC里面的核心控制器DispatcherServlet它负责对请求进行分发到对应的Controller。Controller里面处理完业务逻辑之后返回ModeAndView。然后DispatcherServlet寻找一个或者多个ViewResolver视图解析器找到ModeAndView指定的视图并把数据显示到客户端。 4、Spring MVC的控制器是不是单例模式,如果是,有什么问题,怎么解决
答是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面不能写字段。
5、MVC是什么MVC设计模式的好处有哪些
mvc是一种设计模式设计模式就是日常开发中编写代码的一种好的方法和经验的总结。模型model-视图view-控制器controller三层架构的设计模式。用于实现前端页面的展现与后端业务数据处理的分离。
mvc设计模式的好处
分层设计实现了业务系统各个组件之间的解耦有利于业务系统的可扩展性可维护性。有利于系统的并行开发提升开发效率。
6、Spring MVC常用的注解有哪些 7、Spring MVC怎么样设定重定向和转发的
转发在返回值前面加forward:“譬如forward:user.do?namemethod4”重定向在返回值前面加redirect:“如redirect:http://www.baidu.com”
MyBatis
1、介绍一下MyBatis
MyBatis 是一款优秀的持久层框架一个半 ORM对象关系映射框架它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJOPlain Old Java Objects普通老式 Java 对象为数据库中的记录。
2、ORM是什么
ORMObject Relational Mapping对象关系映射是一种为了解决关系型数据库数据与简单Java对象POJO的映射关系的技术。简单的说ORM是通过使用描述对象和数据库之间映射的元数据将程序中的对象自动持久化到关系型数据库中。
3、为什么说Mybatis是半自动ORM映射工具它与全自动的区别在哪里
Hibernate属于全自动ORM映射工具使用Hibernate查询关联对象或者关联集合对象时可以根据对象关系模型直接获取所以它是全自动的。
而Mybatis在查询关联对象或关联集合对象时需要手动编写sql来完成所以称之为半自动ORM映射工具。
4、传统JDBC开发存在的问题
频繁创建数据库连接对象、释放容易造成系统资源浪费影响系统性能。可以使用连接池解决这个问题。但是使用jdbc需要自己实现连接池。sql语句定义、参数设置、结果集处理存在硬编码。实际项目中sql语句变化的可能性较大一旦发生变化需要修改java代码系统需要重新编译重新发布。不好维护。使用preparedStatement向占有位符号传参数存在硬编码因为sql语句的where条件不一定可能多也可能少修改sql还要修改代码系统不易维护。结果集处理存在重复代码处理麻烦。如果可以映射成Java对象会比较方便
5、JDBC编程有哪些不足之处MyBatis是如何解决这些问题的 6、Mybatis优缺点 7、Hibernate 和 MyBatis 的区别
相同点
都是对jdbc的封装都是持久层的框架都用于dao层的开发。
不同点
映射关系
MyBatis 是一个半自动映射的框架配置Java对象与sql语句执行结果的对应关系多表关联关系配置简单Hibernate 是一个全表映射的框架配置Java对象与数据库表的对应关系多表关联关系配置复杂
SQL优化和移植性
Hibernate 对SQL语句封装提供了日志、缓存、级联级联比 MyBatis 强大等特性此外还提供 HQLHibernate Query Language操作数据库数据库无关性支持好但会多消耗性能。如果项目需要支持多种数据库代码开发量少但SQL语句优化困难。MyBatis 需要手动编写 SQL支持动态 SQL、处理列表、动态生成表名、支持存储过程。开发工作量相对大些。直接使用SQL语句操作数据库不支持数据库无关性但sql语句优化容易。
开发难易程度和学习成本
Hibernate 是重量级框架学习使用门槛高适合于需求相对稳定中小型的项目比如办公自动化系统MyBatis 是轻量级框架学习使用门槛低适合于需求变化频繁大型的项目比如互联网电子商务系统
总结
MyBatis 是一个小巧、方便、高效、简单、直接、半自动化的持久层框架Hibernate 是一个强大、方便、高效、复杂、间接、全自动化的持久层框架。
8、MyBatis编程步骤是什么样的
1、 创建SqlSessionFactory
2、 通过SqlSessionFactory创建SqlSession
3、 通过sqlsession执行数据库操作
4、 调用session.commit()提交事务
5、 调用session.close()关闭会话
9、请说说MyBatis的工作原理
读取 MyBatis 配置文件mybatis-config.xml 为 MyBatis 的全局配置文件配置了 MyBatis 的运行环境等信息例如数据库连接信息。加载映射文件。映射文件即 SQL 映射文件该文件中配置了操作数据库的 SQL 语句需要在 MyBatis 配置文件 mybatis-config.xml 中加载。mybatis-config.xml 文件可以加载多个映射文件每个文件对应数据库中的一张表。造会话工厂通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。创建会话对象由会话工厂创建 SqlSession 对象该对象中包含了执行 SQL 语句的所有方法。Executor 执行器MyBatis 底层定义了一个 Executor 接口来操作数据库它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句同时负责查询缓存的维护。MappedStatement 对象在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数该参数是对映射信息的封装用于存储要映射的 SQL 语句的 id、参数等信息。输入参数映射输入参数类型可以是 Map、List 等集合类型也可以是基本数据类型和 POJO 类型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程。输出结果映射输出结果类型可以是 Map、 List 等集合类型也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程。
10、Mybatis都有哪些Executor执行器它们之间的区别是什么
Mybatis有三种基本的Executor执行器SimpleExecutor、ReuseExecutor、BatchExecutor。 SimpleExecutor每执行一次update或select就开启一个Statement对象用完立刻关闭Statement对象。ReuseExecutor执行update或select以sql作为key查找Statement对象存在就使用不存在就创建用完后不关闭Statement对象而是放置于MapString, Statement内供下一次使用。简言之就是重复使用Statement对象。BatchExecutor执行update没有selectJDBC批处理不支持select将所有sql都添加到批处理中addBatch()等待统一执行executeBatch()它缓存了多个Statement对象每个Statement对象都是addBatch()完毕后等待逐一执行executeBatch()批处理。与JDBC批处理相同。
作用范围Executor的这些特点都严格限制在SqlSession生命周期范围内。
11、Mybatis是否支持延迟加载如果支持它的实现原理是什么 Mybatis仅支持association关联对象和collection关联集合对象的延迟加载association指的就是一对一collection指的就是一对多查询。在Mybatis配置文件中可以配置是否启用延迟加载lazyLoadingEnabledtrue|false。 它的原理是使用CGLIB创建目标对象的代理对象当调用目标方法时进入拦截器方法比如调用a.getB().getName()拦截器invoke()方法发现a.getB()是null值那么就会单独发送事先保存好的查询关联B对象的sql把B查询上来然后调用a.setB(b)于是a的对象b属性就有值了接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。 当然了不光是Mybatis几乎所有的包括Hibernate支持延迟加载的原理都是一样的。 12、MyBatis#{}和${}的区别
#{}是占位符预编译处理${}是拼接符字符串替换没有预编译处理。Mybatis在处理#{}时#{}传入参数是以字符串传入会将SQL中的#{}替换为?号调用PreparedStatement的set方法来赋值。Mybatis在处理时 是 原 值 传 入 就 是 把 {}时是原值传入就是把时是原值传入就是把{}替换成变量的值相当于JDBC中的Statement编译。变量替换后#{} 对应的变量自动加上单引号 ‘’变量替换后${} 对应的变量不会加上单引号 ‘’#{} 可以有效的防止SQL注入提高系统安全性${} 不能防止SQL 注入#{} 的变量替换是在DBMS 中${} 的变量替换是在 DBMS 外
13、MyBatis如何获取生成的主键
对于支持主键自增的数据库MySQL 14、使用MyBatis的mapper接口调用时有哪些要求
Mapper接口方法名和mapper.xml中定义的每个sql的id相同。Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同。Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同。Mapper.xml文件中的namespace即是mapper接口的类路径。
15、Mybatis是如何将sql执行结果封装为目标对象并返回的都有哪些映射形式 第一种是使用标签逐一定义列名和对象属性名之间的映射关系。 第二种是使用sql列的别名功能将列别名书写为对象属性名比如T_NAME AS NAME对象属性名一般是name小写但是列名不区分大小写Mybatis会忽略列名大小写智能找到与之对应对象属性名你甚至可以写成T_NAME AS NaMeMybatis一样可以正常工作。 有了列名与属性名的映射关系后Mybatis通过反射创建对象同时使用反射给对象的属性逐一赋值并返回那些找不到映射关系的属性是无法完成赋值的。 16、MyBatis实现一对一一对多有几种方式怎么操作的 有联合查询和嵌套查询。联合查询是几个表联合查询只查询一次通过在resultMap里面的associationcollection节点配置一对一一对多的类就可以完成 嵌套查询是先查一个表根据这个表里面的结果的外键id去再另外一个表里面查询数据也是通过配置associationcollection但另外一个表的查询通过select节点配置。 17、Mybatis动态sql是做什么的都有哪些动态sql能简述一下动态sql的执行原理不 Mybatis动态sql可以让我们在Xml映射文件内以标签的形式编写动态sql完成逻辑判断和动态拼接sql的功能Mybatis提供了9种动态sql标签trim|where|set|foreach|if|choose|when|otherwise|bind。 其执行原理为使用OGNL从sql参数对象中计算表达式的值根据表达式的值动态拼接sql以此来完成动态sql的功能。 18、Mybatis是如何进行分页的分页插件的原理是什么 Mybatis使用RowBounds对象进行分页它是针对ResultSet结果集执行的内存分页而非物理分页可以在sql内直接书写带有物理分页的参数来完成物理分页功能也可以使用分页插件来完成物理分页。 分页插件的基本原理是使用Mybatis提供的插件接口实现自定义插件在插件的拦截方法内拦截待执行的sql然后重写sql根据dialect方言添加对应的物理分页语句和物理分页参数。 举例select * from student拦截sql后重写为select t.* from (select * from student) t limit 0, 10 19、Mybatis的一级、二级缓存
一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存其存储作用域为 Session当 Session flush 或 close 之后该 Session 中的所有 Cache 就将清空默认打开一级缓存。二级缓存与一级缓存其机制相同默认也是采用 PerpetualCacheHashMap 存储不同在于其存储作用域为 Mapper(Namespace)并且可自定义存储源如 Ehcache。默认不打开二级缓存要开启二级缓存使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置 对于缓存数据更新机制当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了C/U/D 操作后默认该作用域下所有 select 中的缓存将被 clear。
SSM
1、SSM分工
1Spring 作为基础框架整合其他框架
2SpringMVC 作为Web开发框架提供服务期开发支持
3MyBatis 作为ORM框架提供数据库开发支持
八、SpringBoot面试题
1、什么是SpringBoot
Spring Boot 是 Spring 开源组织下的子项目是 Spring 组件一站式解决方案主要是简化了使用 Spring 的难度简省了繁重的配置提供了各种启动器开发者能快速上手。
2、Spring Boot 有哪些优点
容易上手提升开发效率为 Spring 开发提供一个更快、更广泛的入门体验。开箱即用远离繁琐的配置。提供了一系列大型项目通用的非业务性功能例如内嵌服务器、安全管理、运行数据监控、运行状况检查和外部化配置等。没有代码生成也不需要XML配置。避免大量的 Maven 导入和各种版本冲突。
3、Spring Boot 的核心注解是哪个它主要由哪几个注解组成的 启动类上面的注解是SpringBootApplication它也是 Spring Boot 的核心注解主要组合包含了以下 3 个注解 SpringBootConfiguration组合了 Configuration 注解实现配置文件的功能。 EnableAutoConfiguration打开自动配置的功能也可以关闭某个自动配置的选项如关闭数据源自动配置功能 SpringBootApplication(exclude { DataSourceAutoConfiguration.class })。 ComponentScanSpring组件扫描。 4、Spring Boot 自动配置原理是什么 自动装配简单来说就是自动把第三方组件的Bean装载到SpringIOC器里面不需要开发人员再去写Bean的装配配置。 在SpringBoot应用里面只需要在启动类加上SpringBootApplication注解就可以实现自动装配。 SpringBootApplication是一个复合注解真正实现自动装配的注解是EnableAutoConfiguration。 自动装配的实现主要依靠三个核心关键技术。 引入Starter启动依赖组件的时候这个组件里面必须要包含Configuration配置类在这个配置类里面通过Bean注解声明需要装配到IOC容器的Bean对象。 这个配置类是放在第三方的jar包里面然后通过SpringBoot中的约定优于配置思想把这个配置类的全路径放在classpath:/META-INF/spring.factories文件中。这样SpringBoot就可以知道第三方jar包里面的配置类的位置这个步骤主要是用到了Spring里面的SpringFactoriesLoader来完成的。 SpringBoot拿到所第三方jar包里面声明的配置类以后再通过Spring提供的ImportSelector接口实现对这些配置类的动态加载。 在我看来SpringBoot是约定优于配置这一理念下的产物所以在很多的地方都会看到这类的思想。它的出现让开发人员更加聚焦在了业务代码的编写上而不需要去关心和业务无关的配置。 其实自动装配的思想在SpringFramework3.x版本里面的Enable注解就有了实现的雏形。Enable注解是模块驱动的意思我们只需要增加某个Enable注解就自动打开某个功能而不需要针对这个功能去做Bean的配置Enable底层也是帮我们去自动完成这个模块相关Bean的注入。以上就是我对SpringBoot自动装配机制的理解。
5、Spring Boot 配置加载顺序详解
1、properties文件
2、YAML文件
3、系统环境变量
4、命令行参数
6、YAML 配置的优势在哪里 ?
YAML 现在可以算是非常流行的一种配置文件格式了无论是前端还是后端都可以见到 YAML 配置。那么 YAML 配置和传统的 properties 配置相比到底有哪些优势呢
配置有序在一些特殊的场景下配置有序很关键支持数组数组中的元素可以是基本数据类型也可以是对象简洁
7、Spring Boot 中如何解决跨域问题 ? 跨域可以在前端通过 JSONP 来解决但是 JSONP 只可以发送 GET 请求无法发送其他类型的请求在 RESTful 风格的应用中就显得非常鸡肋因此我们推荐在后端通过 CORSCross-origin resource sharing 来解决跨域问题。这种解决方案并非 Spring Boot 特有的在传统的 SSM 框架中就可以通过 CORS 来解决跨域问题只不过之前我们是在 XML 文件中配置 CORS 现在可以通过实现WebMvcConfigurer接口然后重写addCorsMappings方法解决跨域问题。 8、SpringBoot打成的jar和普通的jar有什么区别?
Spring Boot 项目最终打包成的 jar 是可执行 jar 这种 jar 可以直接通过 java -jar xxx.jar 命令来运行
这种 jar 不可以作为普通的 jar 被其他项目依赖即使依赖了也无法使用其中的类。
Spring Boot 的 jar 无法被其他项目依赖主要还是他和普通 jar 的结构不同。普通的 jar 包解压后直、接就是包名包里就是我们的代码而 Spring Boot 打包成的可执行 jar 解压后在 \BOOT-INF\classes目录下才是我们的代码因此无法被直接引用。如果非要引用可以在 pom.xml 文件中增加配置将Spring Boot 项目打包成两个 jar 一个可执行一个可引用。
9、什么是YAML
YAML是一种人类可读的数据序列化语言。它通常用于配置文件。 与属性文件相比如果我们想要在配置文件中添加复杂的属性YAML文件就更加结构化而且更少混淆。可以看出YAML具有分层配置数据。
10、Spring Boot、Spring MVC 和 Spring 有什么区别
SpringSpring最重要的特征是依赖注入。所有 SpringModules 不是依赖注入就是 IOC 控制反转。当我们恰当的使用 DI 或者是 IOC 的时候我们可以开发松耦合应用。松耦合应用的单元测试可以很容易的进行。Spring MVCSpring MVC 提供了一种分离式的方法来开发 Web 应用。通过运用像 DispatcherServeletMoudlAndView 和 ViewResolver 等一些简单的概念开发 Web 应用将会变的非常简单。SpringBootSpring 和 SpringMVC 的问题在于需要配置大量的参数。
11、Spring Boot 中如何解决跨域问题 ?
跨域可以在前端通过 JSONP 来解决但是 JSONP 只可以发送 GET 请求无法发送其他类型的请求在RESTful 风格的应用中就显得非常鸡肋因此我们推荐在后端通过 CORSCross-origin resourcesharing 来解决跨域问题。这种解决方案并非 Spring Boot 特有的在传统的 SSM 框架中就可以通过 CORS 来解决跨域问题只不过之前我们是在 XML 文件中配置 CORS 现在可以通过实现
WebMvcConfigurer接口然后重写addCorsMappings方法解决跨域问题。
12、什么是 CSRF 攻击 CSRF 代表跨站请求伪造。这是一种攻击迫使最终用户在当前通过身份验证的Web 应用程序上执行不需要的操作。CSRF 攻击专门针对状态改变请求而不是数据窃取因为攻击者无法查看对伪造请求的响应。 14、SpringBoot支持哪些日志框架推荐和默认的日志框架是哪个 Spring Boot 支持 Java Util Logging, Log4j2, Lockback 作为日志框架如果你使用 Starters 启动器Spring Boot 将使用 Logback 作为默认日志框架但是不管是那种日志框架他都支持将配置文件输出到控制台或者文件中。 15、SpringBoot Starter的工作原理 我个人理解SpringBoot就是由各种Starter组合起来的我们自己也可以开发Starter在sprinBoot启动时由SpringBootApplication注解会自动去maven中读取每个starter中的spring.factories文件,该文件里配置了所有需要被创建spring容器中的bean并且进行自动配置把bean注入SpringContext中 //SpringContext是Spring的配置文件 16、SpringBoot多数据源事务如何管理
第一种方式是在service层的TransactionManager中使用transactionManager指定DataSourceConfig中配置的事务第二种是使用jta-atomikos实现分布式事务管理
17、SpringBoot中如何实现定时任务 ?
在 Spring Boot 中使用定时任务主要有两种不同的方式一个就是使用 Spring 中的 Scheduled 注解另一-个则是使用第三方框架 Quartz。使用 Spring 中的 Scheduled 的方式主要通过 Scheduled 注解来实现。
18、spring-boot-starter-parent有什么用? 我们都知道新创建一个 Spring Boot 项目默认都是有 parent 的这个 parent 就是 springboot-starter-parent spring-boot-starter-parent 主要有如下作用1. 定义了 Java 编译版本为 1.8 。2. 使用 UTF-8 格式编码。3. 继承自 spring-boot-dependencies这个里边定义了依赖的版本也正是因为继承了这个依赖所以我们在写依赖时才不需要写版本号。4. 执行打包操作的配置。5. 自动化的资源过滤。6. 自动化的插件配置。7. 针对 application.properties 和 application.yml 的资源过滤包括通过 profile 定义的不同环境的配置文件例如 application-dev.properties 和 application-dev.yml。 九、SpringCloud微服务面试题
1、什么是SpringCloud
Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发如服务发现注册、配置中心、智能路由、消息总线、负载均衡、断路器、数据监控等都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子它只是将各家公司开发的比较成熟、经得起实际考验的服务框架组合起来通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
2、互联网架构演进
1、单体应用架构
项目所有功能模块放在一个工程中编码、编译、打包部署在一个tomcat容器中。
简单实用、便于维护、成本低。
**优点**高效开发、架构简单、易于测试、易于部署。
**缺点**可靠性差、复杂性高、扩展能力受限。
2、垂直应用架构
为了业务之间互不影响提高效率、减少组件之间的依赖。
优点流量分担解决并发问题
可以针对不同模块进行优化
方便水平扩展、负载均衡、容错率高
系统间相互独立互不影响业务迭代更高效。
**缺点**服务之间相互调用端口发生改变得手动改变
搭建集群之后实现负载均衡比较复杂
服务之间调用方式不统一
服务监控不到位。
3、SOA应用架构
Dubbo 高性能、轻量级的开源java RPC框架可以和Spring框架无缝集成。
核心功能面向接口的远程方法调用
智能容错和负载均衡
服务自动注册和发现。
**优点**分布式、松耦合、扩展灵活、可重用。
缺点服务抽取力度较大服务调用方和提供耦合度较高。
4、微服务应用架构
拆分粒度更小服务更独立。微小、独立、轻量级通信。
重点业务需要彻底组件化服务化。
优点
微小便于特定服务的聚焦解耦、便于实施敏捷开发。
便于重用和模块之间的组装
独立松耦合不同的微服务可以使用不同的语言开发。
更容易引进新的技术。
缺点
分布式复杂难以管理。
分布式链路跟踪难。
3、什么是服务注册与服务发现。
服务注册提供者将所提供服务的信息服务器IP和端口、访问协议
服务发现消费者从中获取到服务列表。
Eureka 服务注册和发现可以在这种情况下提供帮助。由于所有服务都在 Eureka 服务器上注册并通过调用 Eureka 服务器完成查找因此无需处理服务地点的任何更改和处理。
4、SpringBoot和SpringCloud的区别
SpringBoot专注于快速方便的开发单个个体微服务。SpringCloud是关注全局的微服务协调整理治理框架它将SpringBoot开发的一个个单体微服务整合并管理起来为各个微服务之间提供配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务SpringBoot可以离开SpringCloud独立使用开发项目 但是SpringCloud离不开SpringBoot 属于依赖的关系SpringBoot专注于快速、方便的开发单个微服务个体SpringCloud关注全局的服务治理框架。
5、Spring Cloud的优缺点有哪些 优点 服务拆分粒度更细有利于资源重复利用有利于提高开发效率可以更精准的制定优化服务方案提高系统的可维护性微服务架构采用去中心化思想服务之间采用Restful等轻量级通讯比ESB更轻量适于互联网时代产品迭代周期更短 缺点 微服务过多治理成本高不利于维护系统分布式系统开发的成本高容错分布式事务等对团队挑战大 总的来说优点大过于缺点目前看来SpringCloud是一套非常完善的分布式框架目前很多企业开始用微服务、Spring Cloud的优势是显而易见的。因此对于想研究微服务架构的同学来说学习 Spring Cloud 是一个不错的选择。 6、Eureka的服务治理是什么
Spring Cloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务治理。
在传统的rpc远程调用框架中管理每个服务与服务之间依赖关系比较复杂管理比较复杂所以需要使用服务治理管理服务于服务之间依赖关系可以实现服务调用、负载均衡、容错等实现服务发现与注册。
7、Eureka的服务注册是什么 Eureka采用了CS的设计架构Eureka Server 作为服务注册功能的服务器它是服务注册中心。而系统中的其他微服务使用 Eureka的客户端连接到 Eureka Server并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。 在服务注册与发现中有一个注册中心。当服务器启动的时候会把当前自己服务器的信息 比如 服务地址通讯地址等以别名方式注册到注册中心上。另一方消费者|服务提供者以该别名的方式去注册中心上获取到实际的服务通讯地址然后再实现本地RPC调用RPC远程调用框架核心设计思想在于注册中心因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何rpc远程框架中都会有一个注册中心(存放服务地址相关信息(接口地址)) 8、什么是Spring Cloud Ribbon Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。简单的说Ribbon是Netflix发布的开源项目主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时重试等。简单的说就是在配置文件中列出Load Balancer简称LB后面所有的机器Ribbon会自动的帮助你基于某种规则如简单轮询随机连接等去连接这些机器。 9、Nginx和Ribbon的区别 Nginx是反向代理同时可以实现负载均衡nginx拦截客户端请求采用负载均衡策略根据upstream配置进行转发相当于请求通过nginx服务器进行转发。Ribbon是客户端负载均衡从注册中心读取目标服务器信息然后客户端采用轮询策略对服务直接访问全程在客户端操作 10、Ribbon支持的负载均衡算法
轮询策略随机策略重试策略最小连接数策略可用过略策略区域权衡策略
11、服务器雪崩
一种因“服务提供者不可用”导致“服务调用这不可用”并将不可用逐渐扩大的现象。
形成原因
1服务提供者不可用硬件故障、程序bug、缓存击穿、用户大量请求
2重试加大请求流量用户重试、代码逻辑重试
3服务调者不可用同步等待造成的资源耗尽
解决方案
1服务器熔断
2服务降级
3服务限流
12、Hystrix熔断器
一个延迟和容错库用于隔离访问远程系统、服务或者第三方库防止级联失败提升系统的可用性与容错性。
包裹请求跳闸机制资源隔离监控回退机制自我修复
13、Feign
轻量级HTTP服务客户端发送请求、远程调用。
本质封装了Http调用流程更符合面向接口化的编程习惯类似于Dubbo的服务调用。
对熔断的支持
客户端工程配置文件中开启支持超时时长设置。
1开启Hystrix后Feign中的方法进行一个管理一旦出问题就进入对应的回退逻辑处理。
2当有两个超时时间设置熔断的时候根据两个时间的最小值进行。
14、Gateway的作用
网关的作用是负载均衡、路由转发、请求过虑等。项目中网关与Nginx配合使用
15、Gateway的工作流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TwNNoD45-1676522455054)(https://edu–learn.oss-cn-beijing.aliyuncs.com/weixin/%E5%9B%BE%E7%89%873.png)]
16、Gateway的路由规则
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zjenkbPD-1676522455055)(https://edu–learn.oss-cn-beijing.aliyuncs.com/weixin/%E5%9B%BE%E7%89%874.png)]
17、Gateway的过滤使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qStL5wli-1676522455056)(https://edu–learn.oss-cn-beijing.aliyuncs.com/weixin/%E5%9B%BE%E7%89%875.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gvwwDUdy-1676522455056)(https://edu–learn.oss-cn-beijing.aliyuncs.com/weixin/%E5%9B%BE%E7%89%876.png)]
GlobalFilter全局过滤器是程序员使用比较多的过滤器可以在过滤器中完成鉴权、流量控制、IP黑白名单、权限控制、日志监控等。
18、什么是Spring Cloud Alibaba? Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。 19、Spring Cloud Alibaba有哪些功能 服务限流降级默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ 限流降级功能的接入可以在运行时通过控制台实时修改限流降级规则还支持查看限流降级 Metrics 监控。服务注册与发现适配 Spring Cloud 服务注册与发现标准默认集成了 Ribbon 的支持。分布式配置管理支持分布式系统中的外部化配置配置更改时自动刷新。消息驱动能力基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。分布式事务使用 GlobalTransactional 注解 高效并且对业务零侵入地解决分布式事务问题。阿里云对象存储阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。分布式任务调度提供秒级、精准、高可靠、高可用的定时基于 Cron 表达式任务调度服务。同时提供分布式的任务执行模型如网格任务。网格任务支持海量子任务均匀分配到所有 Workerschedulerx-client上执行。阿里云短信服务覆盖全球的短信服务友好、高效、智能的互联化通讯能力帮助企业迅速搭建客户触达通道。 20、Spring Cloud Alibaba的常用组件有哪些 Sentinel (opens new window)把流量作为切入点从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 Nacos (opens new window)一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 RocketMQ (opens new window)一款开源的分布式消息系统基于高可用分布式集群技术提供低延时的、高可靠的消息发布与订阅服务。 Dubbo (opens new window)Apache Dubbo™ 是一款高性能 Java RPC 框架。 Seata (opens new window)阿里巴巴开源产品一个易于使用的高性能微服务分布式事务解决方案。 Alibaba Cloud OSS (opens new window): 阿里云对象存储服务Object Storage Service简称 OSS是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。 Alibaba Cloud SchedulerX (opens new window): 阿里中间件团队开发的一款分布式任务调度产品提供秒级、精准、高可靠、高可用的定时基于 Cron 表达式任务调度服务。 Alibaba Cloud SMS (opens new window): 覆盖全球的短信服务友好、高效、智能的互联化通讯能力帮助企业迅速搭建客户触达通道。 21、什么是Nacos 前面组件中也有简单介绍Nacos命名的由来前四个字母分别是Naming和Configuration的前两个字母后面的s是Service Nacos是一个易于使用的动态服务发现配置和服务管理平台用于构建云本机应用程序。使用Spring Cloud Alibaba Nacos Discovery您可以基于Spring Cloud的编程模型快速访问Nacos服务注册功能。 Nacos就是注册中心配置中心的组合 22、Nacos有什么作用 替代Eureka做服务注册替代Config做配置中心 服务发现与服务健康检查 Nacos使服务更容易注册并通过DNS或HTTP接口发现其他服务Nacos还提供服务的实时健康检查以防 止向不健康的主机或服务实例发送请求。动态配置管理 动态配置服务允许您在所有环境中以集中和动态的方式管理所有服务的配置。Nacos消除了在更新配置时重新 部署应用程序这使配置的更改更加高效和灵活。动态DNS服务 Nacos提供基于DNS 协议的服务发现能力旨在支持异构语言的服务发现支持将注册在Nacos上的服务以 域名的方式暴露端点让三方应用方便的查阅及发现。服务和元数据管理 Nacos 能让您从微服务平台建设的视角管理数据中心的所有服务及元数据包括管理服务的描述、生命周 期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略。 23、什么是Spring Cloud Seata Seata 是一款开源的分布式事务解决方案致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式为用户打造一站式的分布式解决方案。 十、Redis面试题
1、为什么要用缓存 使用缓存的目的就是提升读写性能。而实际业务场景下更多的是为了提升读性能带来更好的性能带来更高的并发量。Redis的读写性能比Mysql好的多我们就可以把Mysql中的热点数据缓存到Redis中提升读取性能同时也减轻了Mysql的读取压力。 2、使用 Redis有哪些好处
具有以下好处
读取速度快因为数据存在内存中所以数据获取快支持多种数据结构包括字符串、列表、集合、有序集合、哈希等支持事务且操作遵守原子性即对数据的操作要么都执行要么都不支持还拥有其他丰富的功能队列、主从复制、集群、数据持久化等功能。
3、什么是 Redis Redis 是一个开源BSD 许可、基于内存、支持多种数据结构的存储系统可以作为数据库、缓存和消息中间件。它支持的数据结构有字符串strings、哈希hashes、列表lists、集合sets、有序集合sorted sets等除此之外还支持 bitmaps、hyperloglogs 和地理空间geospatial 索引半径查询等功能。 4、为什么Redis单线程模型效率也能那么高
C语言实现效率高纯内存操作基于非阻塞的IO复用模型机制单线程的话就能避免多线程的频繁上下文切换问题丰富的数据结构全称采用hash结构读取速度非常快对数据存储进行了一些优化比如亚索表跳表等
5、为什么 Redis 需要把所有数据放到内存中 Redis 将数据放在内存中有一个好处那就是可以实现最快的对数据读取如果数据存储在硬盘中磁盘 I/O 会严重影响 Redis 的性能。而且 Redis 还提供了数据持久化功能不用担心服务器重启对内存中数据的影响。其次现在硬件越来越便宜的情况下Redis 的使用也被应用得越来越多使得它拥有很大的优势。 6、Redis 的同步机制了解是什么 Redis 支持主从同步、从从同步。如果是第一次进行主从同步主节点需要使用 bgsave 命令再将后续修改操作记录到内存的缓冲区等 RDB 文件全部同步到复制节点复制节点接受完成后将RDB 镜像记载到内存中。等加载完成后复制节点通知主节点将复制期间修改的操作记录同步到复制节点即可完成同步过程。 7、说一下Redis有什么优点和缺点
优点
速度快因为数据存在内存中类似于HashMap HashMap的优势就是查找和操作的时间复杂度都是O (1) 。支持丰富的数据结构支持 String ListSetSorted SetHash 五种基础的数据结构。持久化存储Redis 提供 RDB 和 AOF 两种数据的持久化存储方案解决内存数据库最担心的万一 Redis 挂掉数据会消失掉高可用内置 Redis Sentinel 提供高可用方案实现主从故障自动转移。 内置Redis Cluster提供集群方案实现基于槽的分片方案从而支持更大的 Redis 规模。丰富的特性Key过期、计数、分布式锁、消息队列等。
缺点
由于 Redis 是内存数据库所以单台机器存储的数据量跟机器本身的内存大小。虽然 Redis本身有 Key 过期策略但是还是需要提前预估和节约内存。如果内存增长过快需要定期删除数据。如果进行完整重同步由于需要生成 RDB文件并进行传输会占用主机的 CPU 并会消耗现网的带宽。不过 Redis2.8 版本已经有部分重同步的功能但是还是有可能有完整重同步的。比如新上线的备机。修改配置文件进行重启将硬盘中的数据加载进内存时间比较久。在这个过程中Redis不能提供服务。
8、Redis的淘汰策略
Redis中共有八种内存淘汰策略:
Volatile-lru: 设置了过期时间的Key使用了LRU算法淘汰;Allkeys-lru: 所有key使用LRU算法;Volatile-lfu: 设置了过期时间的key使用了LFU算法淘汰;Allkeys-lfu: 所有key使用了LFU算法淘汰;Volatile-random: 设置了过期时间的key使用随机淘汰;Allkeys-random: 所有key使用随机淘汰;Volatile-ttl: 设置了过期时间的key根据过期时间淘汰,越早过期越早淘汰;Noeviction: 默认策略,当内存达到设置的最大值时,所有申请内存的操作都会报错,(如set,ipush等),只读操作如get命令可以正常执行.
主要是4种算法针对不同的key,形成的策略。
算法
lru 最近很少的使用的key根据时间最不常用的淘汰lfu 最近很少的使用的key (根据计数器用的次数最少的key淘汰)random 随机淘汰ttl 快要过期的先淘汰
9、Redis 为什么设计成单线程的 多线程处理会涉及到锁并且多线程处理会涉及到线程切···换而消耗 CPU。采用单线程避免了不必要的上下文切换和竞争条件。其次 CPU 不是 Redis 的瓶颈Redis 的瓶颈最有可能是机器内存或者网络带宽。 10、Redis五种数据类型
Stringkey-value做缓存Hashkey-fields-values做缓存List有顺序可重复Set无顺序不能重复SortedSet有顺序不能重复
11、Redis集群一般需要几台服务器 因为redis集群至少需要三个节点,要保证集群的高可用,每个节点都要一个备份机.理论上也需要6台虚拟机 12、什么是缓存穿透如何避免
一般的缓存系统都是按照key去缓存查询如果不存在对应的value就应该去后端系统查找比如DB。一些恶意的请求会故意查询不存在的key请求量很大就会对后端系统造成很大的压力。这就叫做缓存穿透解决方案 对查询结果为空的情况也进行缓存缓存时间设置短一点或者该key对应的数据insert了之后清理缓存对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中查询时通过该bitmap过滤
13、什么是缓存雪崩如何避免
当缓存服务器重启或者大量缓存集中在某一个时间段失效这样在失效的时候会给后端系统带来很大压力。导致系统崩溃解决方案 在缓存失效后通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存其他线程等待做二级缓存A1为原始缓存A2为拷贝缓存A1失效时可以访问A2A1缓存失效时间设置为短期A2设置为长期不同的key设置不同的过期时间让缓存失效的时间点尽量均匀
14、Redis 的持久化机制是什么各自的优缺点
持久化机制
RDB默认Redis DataBaseAOF Append Only File
RDB
RDB是Redis默认的持久化方式。
工作机制每隔一段时间就把内存中的数据保存到硬盘上的指定文件中。对应产生的数据文件为dump.rdb
触发RDB的方式有两种手动触发和自动触发 优点 只有一个文件 dump.rdb方便持久化。容灾性好一个文件可以保存到安全的磁盘。性能最大化fork 子进程来完成写操作让主进程继续处理命令所以是 IO 最大化。使用单独子进程来进行持久化主进程不会进行任何 IO 操作保证了 redis 的高性能相对于数据集大时比 AOF 的启动效率更高。 缺点 数据安全性低。RDB 是间隔一段时间进行持久化如果持久化之间 redis 发生故障会发生数据丢失。所以这种方式更适合数据要求不严谨的时候。如果redis要故障时要尽可能少的丢失数据RDB没有AOF好例如1:00进行的快照在1:10又要进行快照的时候宕机了这个时候就会丢失10分钟的数据。RDB每次fork出子进程来执行RDB快照生成文件时如果文件特别大可能会导致客户端提供服务暂停数毫秒或者几秒 AOF AOF 是 以日志的形式来记录每个写操作将每一次对数据进行修改都把新建、修改数据的命令保存到指 定文件中。Redis 重新启 动时读取这个文件重新执行新建、修改数据的命令恢复数据。 当两种方式同时开启时数据恢复Redis会优先选择AOF恢复 优点 数据安全AOF持久化可以配置 appendfsync 属性有 always每进行一次 命令操作就记录到 AOF文件中一次。 通过 append 模式写文件即使中途服务器宕机可以通过 redis-check-aof 工具解决数据一致性问题。 AOF日志文件的命令通过非常可读的方式进行记录这个非常适合做灾难性的误删除紧急恢复如果某人不小心用flushall命令 清空了所有数据只要这个时候还没有执行rewrite那么就可以将日志文件中的flushall删除进行恢复 缺点 对于同一份文件AOF文件比RDB数据快照要大。AOF开启后支持写的QPS会比RDB支持的写的QPS低因为AOF一般会配置成每秒fsync操作每秒的fsync操作还是很高的、数据恢复比较慢不适合做冷备。 十一、中间件相关面试题
RabbitMQ
1、MQ的优势
应用解耦 服务与服务之间不再约定协议而对接接口而是通过生产者/消费者的模式让中间件的MQ来对接两边的数据通信实现解耦合扩展性更强。一步提速 常见的服务通信需要阻塞成功获取到响应状态在写入数据到数据库阻塞同步往下执行。加入MQ后提升用户体验和系统吞吐量。削峰填谷 常见的服务通信当一瞬间有5000个请求给到服务器时服务器最大能处理1000请求受不了了当场去世。加入MQ后先把请求丢到队列中等待处理系统每秒从mq中拉取1000个请求进行处理刚好卡在能处理的1000个真实压榨案例这样就变成了从1秒钟处理5000个请求的高峰期拆分成了5秒钟每秒钟处理1000请求的平缓处理器哦不是满载处理器。
2、你们项目中用到过 MQ 吗谈谈你对 MQ 的理解 我们项目中使用 MQ 主要是做一些异步的操作比如说我们的接口是属于http协议接口它是同步调用如果说接口响应比较慢的情况下会导致客户端同步阻塞等待客户端同步阻塞等待的情况下会引发客户端超时客户端一旦发生超时就会导致客户端触发一些重试的策略而在触发重试的策略过程中会导致业务可能会发生重复执行所以我们就需要注意一些幂等性问题而接口因为它执行比较耗时所以呢我们会将一些执行比较耗时的业务逻辑代码把他直接改成使用 mq 异步去实现能够提高就是我们的 http 协议接口的响应速度比如说异步的去扣库存呢异步的去发短信呢这些场景下我们都是使用到 MQ来进行实现落地的。 3、常用的MQ
1ActiveMQ支持万级的吞吐量较成熟完善
2RabbitMQ延时低微妙级延时
3RocketMQ阿里维护的消息中间件可以达到十万级的吞吐量支持分布式事务。
4Kafka阿里维护的消息中间件可以达到十万级的吞吐量支持分布式事务。
4、MQ消费者消费消息的顺序一致性问题 生产者投递消息过程当中可以设定一个消息 key相同的业务逻辑呢可以设定一个相同的消息 key 在做 hash 的时候最终都会落地到同一个分区来就行存放最终就被同一个消费者进行消费所以想解决消息顺序这些问题它的核心思想就是让我们的这个消息投递存放到同一个分区里面最终被同一个消费者消费。 5、RabbitMQ如何保证数据⼀致性
⽣产者确认机制消息持久化后异步回调通知⽣产者保证消息已经发出去消息持久化设置消息持久化消费者确认机制消费者成功消费消息之后⼿动确认保证消息已经消费。
6、如何确保消息正确地发送⾄RabbitMQ RabbitMQ使⽤发送⽅确认模式确保消息正确地发送到RabbitMQ。 发送⽅确认模式将信道设置成confirm模式发送⽅确认模式则所有在信道上发布的消息都会被指派⼀个唯⼀的ID。⼀旦消息被投递到⽬的队列后或者消息被写⼊磁盘后可持久化的消息信道会发送⼀个确认给⽣产者包含消息唯⼀ID。如果RabbitMQ发⽣内部错误从⽽导致消息丢失会发送⼀条nacknot acknowledged未确认消息。发送⽅确认模式是异步的⽣产者应⽤程序在等待确认的同时可以继续发送消息。当确认消息到达⽣产者应⽤程序⽣产者应⽤程序的回调⽅法就会被触发来处理确认消息。 7、如何避免消息重复投递或重复消费 在消息⽣产时MQ内部针对每条⽣产者发送的消息⽣成⼀个inner-msg-id作为去重和幂等的依据消息投递失败并重传避免重复的消息进⼊队列在消息消费时要求消息体中必须要有⼀个bizId对于同⼀业务全局唯⼀如⽀付ID、订单ID、帖⼦ID等作为去重和幂等的依据避免同⼀条消息被重复消费。 8、RabbitMQ的工作模式
一.simple模式即最简单的收发模式 二.work工作模式(资源的竞争) 三.publish/subscribe发布订阅(共享资源) 四.routing路由模式 五.topic 主题模式(路由模式的一种) ElasticSearch
1、elasticsearch 了解多少说说你们公司 es 的集群架构索引数据大小分片有多少以及一些调优手段
面试官想了解应聘者之前公司接触的 ES 使用场景、规模有没有做过比较大规模的索引设计、规划、调优。解答如实结合自己的实践场景回答即可。比如ES 集群架构 13 个节点索引根据通道不同共 20索引根据日期每日递增 20索引10分片每日递增 1 亿数据每个通道每天索引大小控制150GB 之内。仅索引层面调优手段 根据业务增量需求采取基于日期模板创建索引通过 roll over API 滚动索引使用别名进行索引管理每天凌晨定时对索引做 force_merge 操作以释放空间采取冷热分离机制热数据存储到 SSD提高检索效率冷数据定期进行 shrink操作以缩减存储采取 curator 进行索引的生命周期管理仅针对需要分词的字段合理的设置分词器Mapping 阶段充分结合各个字段的属性是否需要检索、是否需要存储等。
2、为什么要使用elasticsearch 因为在我们课程中的数据将来会非常多所以采用以往的模糊查询模糊查询前置配置会放弃索引导致课程查询是全表扫面在百万级别的数据库中效率非常低下而我们使用ES做一个全文索引我们将经常查询的课程的某些字段比如说课程名描述、价格还有id这些字段我们放入我们索引库里可以提高查询速度。 3、项目中如何使用elasticsearch 在服务启动时将课程数据从数据库查询出来压入es中在用户进行课程搜索时可以通过课程关键词、讲师名称和价格区间进行数据搜索通过关键词进行搜索时使用了es 的高亮和分页的工具类对查询出来的数据与查询字段相同的进行高亮处理并通过匹配度的高低进行排序。 4、谈谈分词与倒排索引的原理
首先说分词是给检索用的。
英文一个单词一个词很简单。I am a student词与词之间空格分隔。中文我是学生就不能一个字一个字地分我-是-学生。这是好分的。还有歧义的使用户放心使用-户使-用户。人很容易看出机器就难多了。所以市面上有各种各样的分词器一个强调的效率一个强调的准确率。
倒排索引倒排针对的是正排。
正排就是我记得我电脑有个文档讲了 ES 的常见问题总结。那么我就找到文档从上往下翻页找到ES的部分。通过文档找文档内容。倒排一个txt文件ES的常见问题 - D:/分布式问题总结.doc。 所以倒排就是文档内容找文档。当然内容不是全部的否则也不需要找文档了内容就是几个分词而已。这里的txt就是搜索引擎。 Sharing-JDBC
1、ShardsReplicas分片和复制
****分片****将索引划分成多份可以放置在集群任何节点上。1、允许水平分割/扩展内容数量2、允许在分片上进行分布式、并行。
****复制****创建分片的一份或多份拷贝。1、在分片/节点失败的情况下提高了高可用性2、搜索可以在所有复制上运行3、分片和复制的数量可以在索引创建的时候指定。4、复制数量可以在之后动态改变分片数量事后不能再改变。
2、、分库分表
*作用缓解单机和单库带来的性能瓶颈和压力突破网络IO、硬件资源、连接数的瓶颈。*
****方式****垂直分库、水平分库、垂直分表、水平分表。
*垂直拆分原则*1不常用的字段单独放一张表。
2text、blob等大字段拆分放在附表。
3经常组合查询的列放在同一张表中。
3、垂直分库
按照业务进行分类分不到不同的数据库上每个库可以放在不同的数据库上专库专用。
*好处*1业务层面解耦
2对不同的业务数据进行分级管理、维护、监控、扩展。
3高并发场景下提升IO、数据库连接数、降低单机硬件资源的瓶颈。
4、水平分库
把同一张表的数据按一定规则拆到不同的数据库中每个库可以放在不同的服务器上。
****好处****解决了单库大数据高并发的性能瓶颈提高了系统的稳定性和可用性。
5、垂直分表
将一个表按照字段分成多表每个表存储一部分字段。
****好处****1避免IO争抢减少锁表的几率。
2充分发挥热门数据的操作效率。
6、水平分表
在同一个数据库内把同一个表的数据按一定规则拆到多个表中。
****好处****优化单一表数据量过大而产生的性能问题避免IO争抢减少锁表的几率。
7、Sharing-JDBC定义
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7CeRcw3T-1676522455060)(https://edu–learn.oss-cn-beijing.aliyuncs.com/weixin/%E5%9B%BE%E7%89%877.png)]
*当当网研发的开源分布式数据库中间件。*
Docker
1、简介
Docker是一个开源的应用容器引擎开发者可以打包自己的应用到容器里面然后迁移到其他机器的docker应用中可以实现快速部署。
2、Docker基本概念
Client客户端 是Docker的用户端可以接受用户命令和配置标识并与Docker daemon通信。
Images镜像 是一个只读模板含创建Docker容器的说明它与操作系统的安装光盘有点像。
Containers容器 镜像的运行实例镜像与容器的关系类比面向对象中的类和对象。
Registry仓库 是一个集中存储与分发镜像的服务。最常用的Registry是官方的Docker Hub 。
十二、数据结构与算法面试题
1.1 概述
数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关。
JAVA中常见的数据结构有
数组栈Stack队列Queue链表LinkedList树Tree哈希表Hash
1.2 数组
数组是内存中连续保存的多个相同类型的元素的数据结构。通过下标索引访问数组中的元素索引从0开始。根据维度可以分为1维数组、2维数组……N维数组。 优点 通过下标直接定位元素位置查找效率高。 缺点 长度固定数据类型都必须相同插入跟删除元素时效率比较低。
适合场景大量查询很少删除和插入。
1.3 栈
1.3.1 概述
栈结构只能在一端操作该操作端叫做栈顶另一端叫做栈底。栈结构按照“后进先出”Last In First Out, LIFO的方式处理结点数据。
1.4 队列
队列是一种特殊的线性表特殊之处在于它只允许在表的前端front进行删除操作而在表的后端rear进行插入操作和栈一样队列是一种操作受限制的线性表。进行插入操作的端称为队尾进行删除操作的端称为队头。
1.5 链表
链表是一种物理存储单元上非连续、非顺序的存储结构数据元素的逻辑顺序是通过链表中的指针连接次序实现的。每一个链表都包含多个节点节点又包含两个部分一个是数据域储存节点含有的信息一个是引用域储存下一个节点或者上一个节点的地址。
链表的特点
获取数据麻烦需要遍历查找比数组慢插入、删除的效率比较高
链表从结构上分为单向链表跟双向链表。
1.6 树
1.6.1 树
树(Tree)是n(n≥0)个结点的有限集T并且当n0时满足下列条件 1有且仅有一个特定的称为根(Root)的结点 2当n1时其余结点可以划分为m(m0)个互不相交的有限集T1、T2 、…、Tm每个集Ti(1≤i≤m)均为树且称为树T的子树(SubTree)。 特别地不含任何结点(即n0)的树称为空树。
1.6.2 二叉树
二叉树Binary Tree是有限个节点的集合这个集合可以是空集也可以是一个根节点和两颗不相交的子二叉树组成的集合其中一颗树叫根的左子树另一颗树叫右子树。所以二叉树是一个递归地概念。
1.6.3 满二叉树
一棵满二叉树就是高度为k且拥有(2^k)-1个节点的二叉树一棵满二叉树每个节点要么都有两棵子树要么都没有子树而且每一层所有的节点之间必须要么都有两棵子树要么都没子树。
1.6.4 完全二叉树
完全二叉树是一颗特殊的二叉树它遵循以下规则
假设完全二叉树高度为k则完全二叉树需要符合以下两点
所有叶子节点都出现在k层或k-1层并且从1~k-1层必须达到最大节点数。第k层可以是不满的但是第k层的所有节点必须集中在最左边。
1.6.5 二叉查找树
二叉查找树(BinarySearch Tree也叫二叉搜索树或二叉排序树BinarySort Tree)或者是一棵空树或者是具有下列性质的二叉树
1、若任意结点的左子树不空则左子树上所有结点的值均小于它的根结点的值
2、若任意结点的右子树不空则右子树上所有节点的值均大于它的根结点的值
3、任意结点的左右子树也分别为二叉查找树
4、没有键值相等的结点。
在实际应用中二叉查找树的使用比较多。
1.6.6 平衡二叉树
平衡二叉树AVL是一种特殊的二叉查找树其中每一个节点的左子树和右子树的高度差至多等于1。从平衡二叉树的名字中可以看出来它是一种高度平衡的二叉排序树。那么什么叫做高度平衡呢意思就是要么它是一颗空树要么它的左子树和右子树都是平衡二叉树且左子树和右子树的深度只差的绝对值绝对不超过1。
1.6.7 红黑树
红黑树Red Black Tree 是一种自平衡二叉查找树。
红黑树的特性 1每个节点或者是黑色或者是红色。 2根节点是黑色。 3每个叶子节点NIL是黑色。 4如果一个节点是红色的则它的子节点必须是黑色的。[注意这里叶子节点是指为空(NIL)的虚节点] 5从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
红黑树跟平衡二叉树的区别 红黑树放弃了追求完全平衡追求大致平衡保证每次插入最多只需要三次旋转就能达到平衡实现起来也更为简单。 平衡二叉树追求绝对平衡条件比较苛刻实现起来比较麻烦每次插入新节点之后需要旋转的次数不能预知。
1.7 哈希表
哈希表Hash table也叫散列表是根据关键码值(Key)而直接进行访问的数据结构。也就是说它通过把关键码值映射到表中一个位置来访问记录以加快查找的速度。这个映射函数叫做散列哈希函数存放记录的数组叫做散列表。
1.7.2 哈希冲突
对应不同的关键字可能获得相同的hash地址即 key1≠key2但是f(key1)f(key2)。这种现象就是冲突而且这种冲突只能尽可能的减少不能完全避免。
常用的冲突解决办法 开放地址法线性探测法 当冲突法生时继续往后查找数组的下一个空位并将数据填入。比如1和101,1占据了一个位置101进入时候就向下查找找到下面的一个空位插入 如果没有继续查找空位直到找到为止并进行插入。 链地址法拉链法 将产生冲突的值以链表的形式连起来。
1.8 对比
每种数据结构有自己的特点跟优缺点见如下表
数据结构优 点缺 点数组插入快查找慢删除慢大小固定只能存储单一元素栈提供后进先出的存取方式存取其他项很慢队列提供先进先出的存取方式存取其他项很慢链表插入快删除快查找慢二叉树如果树是平衡的则查找、插入、删除都快删除算法复杂红黑树查找、删除、插入都快。树总是平衡算法复杂哈希表如果关键字已知则存取极快删除慢如果不知道关键字存取慢对存储空间使用不充分
2、简单算法 /*** 冒泡排序* param arr* return*/public static int[] MaoPao(int [] arr){int temp 0;for (int i 1; i arr.length; i) {for (int j 1; j arr.length-1; j) {if (arr[j]arr[j1]){temp arr[j];arr[j] arr[j1];arr[j1] temp;}}}return arr;}/*** 选择排序* param arr* return*/public static int [] XuanZe(int [] arr){for (int i 0; i arr.length-1; i) {int temp 0;int index i;for (int j i1; j arr.length; j) {if (arr[index]arr[j]){index j;}}temp arr[index];arr[index] arr[i];arr[i] temp;}return arr;}/*** 二分查找* param arr* param value* return*/public static int ErFen(int[] arr,int value){int low 0;int high arr.length-1;while (lowhigh){int mid (lowhigh)/2;if (arr[mid]value){return mid;}else if(arr[mid]value){low mid 1;}else {high mid -1;}}return -1;}3、懒汉和饿汉
/*** 饿汉*/
public class EHan {private static EHan eHan new EHan();private EHan(){}private static EHan getEHan(){return eHan;}
}/*** 懒汉*/
public class LanHan {private static LanHan lanHan null;private LanHan(){}private static LanHan getLanHan(){if (lanHan null){lanHan new LanHan();}return lanHan;}
}冒泡排序
// 优化后的冒泡排序public static void main(String[] args) {int[] arr {3,5,6,8,9,1,2,4,7,7};int k arr.length-1;//初始化第一次排序的遍历范围if (k 0){// 循环次数for (int i arr.length-1; i1; i--) {// 比较次数for (int j 0; j i; j) {// 交换位置if(arr[j] arr[j1]){arr[j] arr[j]^arr[j1];arr[j1] arr[j]^arr[j1];arr[j] arr[j]^arr[j1];k j;System.out.println(j j);}}}}System.out.println(arr Arrays.toString(arr));}选择排序
int[] arr {3,5,2,6,1,8,9,1,2,4,0};int count 0;// 循环次数for (int i 0; i arr.length-1; i) {count;// 第二层循环 i正好是 第二层比较的数中最小的下标intint min i ;for (int j i1; j arr.length; j) {if (arr[j] arr[min]){min j;}}if (i ! min){int temp arr[min];arr[min] arr[i];arr[i] temp;}}System.out.println(比较次数 count);System.out.println(arr Arrays.toString(arr));二分法查找
public static void main(String[] args) {int[ ] arr { 30,20,50,10,80,9,7,12,100,40,8};Scanner sc new Scanner(System.in);System.out.println(请输入你要查找的数 : );int searchWord sc.nextInt();Arrays.sort(arr); //二分法查找之前一定要对数组元素排序System.out.println(Arrays.toString(arr));System.out.println(searchWord元素的索引binarySearch(arr,searchWord));System.out.println();}public static int binarySearch(int[] arr, int value) {// 开始位置int begin 0;// 结束 位置int end arr.length - 1;while(begin end) {int middle (begin end) / 2;//返回查询到的索引位置if (value arr[middle]) {return middle;}if (arr[middle] value) {begin middle 1;}if (arr[middle] value) {end middle - 1;}}//上面循环完毕说明未找到返回-1return -1;}十三、项目相关
1、OA工作流Activiti
定义业务过程部分或整体在计算机应用环境下的自动化
主要解决使在多个参与者之间按照某种预定义的规则传递文档、信息或任务的过程”自动进行“从而实现某个预期的业务目标或者促使此目标的实现。
工作流管理系统
一个完成工作量的定义和管理的软件系统。按照在系统中预先定义好的工作流规则进行工作流实例的执行。
工作流管理系统不是企业的业务系统而是为企业的业务系统的运行提供了一个软件的支撑环境。
主要作用
1、定义工作流包括具体的活动、规则等。
2、执行工作流按照流程定义的规则执行并由多个参与者进行控制。
2、微信登录
1.AppID
应用ID唯一标识身份证号
2.AppSecret
应用的密钥密码
3.code
授权的临时凭证例如临时身份证
4. access_token
接口调用凭证例如真正的身份证虎符令牌 3、微信支付 4、单点登录 5、并发量大的话如何处理
1、数据库优化、分库分表、读写分离、消息队列肖锋
2、单体式架构多线程
分布式微服务、集群、负载均衡熔断、反向代理
6、预计吞吐量
吞入量TPS单位时间内处理请求的数量上线
QPS秒为单位
RT响应时间一般为1-2秒
7、文件上传如何处理断点续传
断点续传断点续传指的是在下载或上传时将下载或上传任务人为的划分为几个部分。
整体思路
拿到文件保存文件唯一性标识切割文件分段上传每次上传一段根据唯一性标识判断文件上传进度直到文件的全部片段上传完毕
8、redis分布式锁怎么实现的当同时有多个······他是怎么处理的
1、秒杀案例需要达到的预期特性
稳即流量符合预期时整体架构要满足高可用就算超出预期也不能掉链子准要保证数据的一致性不能超卖快系统性能要足够高尽可能做好系统优化
版本一 快速搭建一个简单的秒杀系统只需要把你的商品购买页面增加一个“定时上架”功能仅在秒杀开始时才让用户看到购买按钮当商品的库存卖完了也就结束了。版本二
随着请求量的加大比如从 1w/s 到了 10w/s 的量级版本一的架构很快就遇到了瓶颈因此需要做架构改造来提升系统性能。这些架构改造包括1把秒杀系统独立出来打造一个单独的系统这样可以有针对性的优化例如减少淘宝店铺装修的功能减少页面复杂度。2系统独立部署一个集群这样秒杀的大流量不会影响到正常的商品购买集群的机器负载。3将热点数据单独放到一个缓存系统中以提高读性能。4增加秒杀答题防止有秒杀器。版本三
这个架构仍然支持不了超过 100w/s 的请求量所以为了进一步提升秒杀系统的性能我们又对架构做进一步升级。1对页面进行彻底的动静分离使得用户秒杀时不需要刷新整个页面只需要点击抢宝按钮借此把页面刷新的数据降到最少。2在服务端对秒杀商品进行本地缓存不需要再调用依赖系统的后台服务获取数据甚至不需要去公共的缓存集群中查询数据这样不仅可以减少系统调用而且能够避免压垮公共缓存集群。3增加系统限流保护防止最坏情况发生。经过这些优化系统架构变成了下图中的样子。在这里我们对页面进行了进一步的静态化秒杀过程中不需要刷新整个页面而只需要向服务端请求很少的动态数据。而且最关键的详情和交易系统都增加了本地缓存来提前缓存秒杀商品的信息热点数据库也做了独立部署等。一个人进去其他人阻塞进入等待redis持久化数据-1传递到消息队列到数据库。
1、实现分布式锁的思路
因为redis是单线程的所以命令也就具备原子性使用setnx命令实现锁保存k-v 如果k不存在保存当前线程加锁执行完成后删除k表示释放锁如果k已存在阻塞线程执行表示有锁 如果加锁成功在执行业务代码的过程中出现异常导致没有删除k释放锁失败那么就会造成死锁后面的所有线程都无法执行 设置过期时间例如10秒后redis自动删除 高并发下由于时间段等因素导致服务器压力过大或过小每个线程执行的时间不同 第一个线程执行需要13秒执行到第10秒时redis自动过期了k释放锁第二个线程执行需要7秒加锁执行第3秒锁 被释放了为什么是被第一个线程的finally主动deleteKey释放掉了。。。连锁反应当前线程刚加的锁就被其他线程释放掉了周而复始导致锁会永久失效 给每个线程加上唯一的标识UUID随机生成释放的时候判断是否是当前的标识即可
2、Redisson
Redis 是最流行的 NoSQL 数据库解决方案之一而 Java 是世界上最流行注意我没有说“最好”的编程语言之一。虽然两者看起来很自然地在一起“工作”但是要知道Redis 其实并没有对 Java 提供原生支持。相反作为 Java 开发人员我们若想在程序中集成 Redis必须使用 Redis 的第三方库。而 Redisson 就是用于在 Java 程序中操作 Redis 的库它使得我们可以在程序中轻松地使用 Redis。Redisson 在 java.util 中常用接口的基础上为我们提供了一系列具有分布式特性的工具类。
十四、Linux常用命令
文件与目录操作
命令解析cd /home进入 ‘/home’ 目录cd …返回上一级目录cd …/…返回上两级目录cd -返回上次所在目录cp file1 file2将file1复制为file2cp -a dir1 dir2复制一个目录cp -a /tmp/dir1 .复制一个目录到当前工作目录.代表当前目录ls查看目录中的文件ls -a显示隐藏文件ls -l显示详细信息ls -lrt按时间显示文件l表示详细列表r表示反向排序t表示按时间排序pwd显示工作路径mkdir dir1创建 ‘dir1’ 目录mkdir dir1 dir2同时创建两个目录mkdir -p /tmp/dir1/dir2创建一个目录树mv dir1 dir2移动/重命名一个目录rm -f file1删除 ‘file1’rm -rf dir1删除 ‘dir1’ 目录及其子目录内容
查看文件内容
命令解析cat file1从第一个字节开始正向查看文件的内容head -2 file1查看一个文件的前两行more file1查看一个长文件的内容tac file1从最后一行开始反向查看一个文件的内容tail -3 file1查看一个文件的最后三行vi file打开并浏览文件
文本内容处理
命令解析grep str /tmp/test在文件 ‘/tmp/test’ 中查找 “str”grep ^str /tmp/test在文件 ‘/tmp/test’ 中查找以 “str” 开始的行grep [0-9] /tmp/test查找 ‘/tmp/test’ 文件中所有包含数字的行grep str -r /tmp/*在目录 ‘/tmp’ 及其子目录中查找 “str”diff file1 file2找出两个文件的不同处sdiff file1 file2以对比的方式显示两个文件的不同vi file操作解析i进入编辑文本模式Esc退出编辑文本模式:w保存当前修改:q不保存退出vi:wq保存当前修改并退出vi
查询操作
命令解析find / -name file1从 ‘/’ 开始进入根文件系统查找文件和目录find / -user user1查找属于用户 ‘user1’ 的文件和目录find /home/user1 -name *.bin在目录 ‘/ home/user1’ 中查找以 ‘.bin’ 结尾的文件find /usr/bin -type f -atime 100查找在过去100天内未被使用过的执行文件find /usr/bin -type f -mtime -10查找在10天内被创建或者修改过的文件locate *.ps寻找以 ‘.ps’ 结尾的文件先运行 ‘updatedb’ 命令find -name ‘*.[ch]’ | xargs grep -E ‘expr’在当前目录及其子目录所有.c和.h文件中查找 ‘expr’find -type f -print0 | xargs -r0 grep -F ‘expr’在当前目录及其子目录的常规文件中查找 ‘expr’find -maxdepth 1 -type f | xargs grep -F ‘expr’在当前目录中查找 ‘expr’
压缩、解压
命令解析bzip2 file1压缩 file1bunzip2 file1.bz2解压 file1.bz2gzip file1压缩 file1gzip -9 file1最大程度压缩 file1gunzip file1.gz解压 file1.gztar -cvf archive.tar file1把file1打包成 archive.tar-c: 建立压缩档案-v: 显示所有过程-f: 使用档案名字是必须的是最后一个参数tar -cvf archive.tar file1 dir1把 file1dir1 打包成 archive.tartar -tf archive.tar显示一个包中的内容tar -xvf archive.tar释放一个包tar -xvf archive.tar -C /tmp把压缩包释放到 /tmp目录下zip file1.zip file1创建一个zip格式的压缩包zip -r file1.zip file1 dir1把文件和目录压缩成一个zip格式的压缩包unzip file1.zip解压一个zip格式的压缩包到当前目录unzip test.zip -d /tmp/解压一个zip格式的压缩包到 /tmp 目录
yum安装器
命令解析yum -y install [package]下载并安装一个rpm包yum localinstall [package.rpm]安装一个rpm包使用你自己的软件仓库解决所有依赖关系yum -y update更新当前系统中安装的所有rpm包yum update [package]更新一个rpm包yum remove [package]删除一个rpm包yum list列出当前系统中安装的所有包yum search [package]在rpm仓库中搜寻软件包yum clean [package]清除缓存目录/var/cache/yum下的软件包yum clean headers删除所有头文件yum clean all删除所有缓存的包和头文件
网络相关
命令解析ifconfig eth0显示一个以太网卡的配置ifconfig eth0 192.168.1.1 netmask 255.255.255.0配置网卡的IP地址ifdown eth0禁用 ‘eth0’ 网络设备ifup eth0启用 ‘eth0’ 网络设备iwconfig eth1显示一个无线网卡的配置iwlist scan显示无线网络ip addr show显示网卡的IP地址
系统相关
命令解析su -切换到root权限与su有区别shutdown -h now关机shutdown -r now重启top罗列使用CPU资源最多的linux任务 输入q退出pstree以树状图显示程序man ping查看参考手册例如ping 命令passwd修改密码df -h显示磁盘的使用情况cal -3显示前一个月当前月以及下一个月的月历cal 10 1988显示指定月年的月历date –date ‘1970-01-01 UTC 1427888888 seconds’把一相对于1970-01-01 00:00的秒数转换成时间
十五、JavaWeb面试题
1、什么是Servlet
Servlet是一门用于开发动态web资源的技术它是运行在服务器端的小程序。
Servlet就是一个接口定义了Java类被浏览器访问到(tomcat识别)的规则。
作用Servlet主要用于处理客户端传来的HTTP请求并返回一个响应它能够处理的请求有doGet()和doPost()等方法。
用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据)需要完成以下2个步骤
编写一个Java类实现Servlet接口。把开发好的Java类部署到web服务器中。
2、什么是Servlet对象的生命周期
Servlet对象什么时候被创建。Servlet对象什么时候被销毁。Servlet对象创建了几个Servlet对象的生命周期表示一个Servlet对象从出生在最后的死亡整个过程是怎样的。
我们不需要在程序创建Servlet的对象也没有去调用对象上的方法。Servlet对象的生命周期由web服务器负责
3、JSP九大内置对象
pageContext页面上下文对象相当于页面中所有功能的集合通过它可以获取JSP页面的out、request、response、session、application对象。requestresponsesessionapplication应用程序对象application实现了用户间数据的共享可存放全局变量它开始于服务器启动知道服务器关闭。page就是JSP本身。exceptionoutout用于在web浏览器内输出信息并且管理应用服务器上的输出缓冲区作用域page。config取得服务器的配置信息。
4、JSP和Servlet的区别
1servlet是服务器端的Java程序它担当客户端和服务端的中间层。
2JSP全名为Java server pages中文名叫Java服务器页面其本质是一个简化的servlet设计。JSP是一种动态页面设计它的主要目的是将表示逻辑从servlet中分离出来。
3JVM只能识别Java代码不能识别JSPJSP编译后变成了servletweb容器将JSP的代码编译成JVM能够识别的Java类servlet。
4JSP有内置对象、servlet没有内置对象。
5、转发和重定向的区别
重定向访问服务器两次转发只访问服务器一次。转发页面的URL不会改变而重定向地址会改变转发只能转发到自己的web应用内重定向可以重定义到任意资源路径。转发相当于服务器跳转相当于方法调用在执行当前文件的过程中转向执行目标文件两个文件(当前文件和目标文件)属于同一次请求前后页 共用一个request可以通过此来传递一些数据或者session信息request.setAttribute()和 request.getAttribute()。而重定向会产生一个新的request不能共享request域信息与请求参数由于转发相当于服务器内部方法调用所以转发后面的代码仍然会执行(转发之后记得return)重定向代码执行之后是方法执行完成之后进行重定向操作也就是访问第二个请求如果是方法的最后一行进行重定向那就会马上进行重定向(重定向也需要return)。无论是RequestDispatcher.forward方法还是HttpServletResponse.sendRedirect方法在调用它们之前都不能有内容已经被实际输出到了客户端。如果缓冲区中已经有了一些内容这些内容将被从缓冲区中移除。
6、session 和 cookie 有什么区别
1存储位置不同
cookie在客户端浏览器session在服务器
2存储容量不同
cookie4K一个站点最多保留20个cookiesession没有上线出于对服务器的保护session内不可存过多东西并且要设置session删除机制
3存储方式不同
cookie只能保存ASCII字符串并需要通过编码方式存储为Unicode字符或者二进制数据session中能存储任何类型的数据包括并不局限于String、integer、list、map等
4隐私策略不同
cookie对客户端是可见的不安全session存储在服务器上安全
5有效期不同
开发可以通过设置cookie的属性达到使cookie长期有效的效果session依赖于名为JESSIONID的cookie而cookie JSESSIONID的过期时间默认为-1只需关闭窗口该session就会失效因而session达不到长期有效的效果
6跨域支持上不同
cookie支持跨域session不支持跨域
7、get和post的区别
get请求参数是连接在url后面的,而post请求参数是存放在requestbody内的get请求因为浏览器对url长度有限制所以参数个数有限制而post请求参数个数没有限制因为get请求参数暴露在url上,所以安全方面post比get更加安全get请求只能进行url编码,而post请求可以支持多种编码方式get请求参数会保存在浏览器历史记录内,post请求并不会get请求浏览器会主动cache,post并不会,除非主动设置get请求产生1个tcp数据包,post请求产生2个tcp数据包在浏览器进行回退操作时,get请求是无害的,而post请求则会重新请求一次浏览器在发送get请求时会将header和data一起发送给服务器,服务器返回200状态码,而在发送post请求时,会先将header发送给服务器,服务器返回100,之后再将data发送给服务器,服务器返回200 OK
8、说一下 session 的工作原理
当客户端登录完成后会在服务端产生一个session此时服务端会将sessionid返回给客户端浏览器。客户端将sessionid储存在浏览器的cookie中当用户再次登录时会获得对应的sessionid然后将sessionid发送到服务端请求登录服务端在内存中找到对应的sessionid完成登录如果找不到返回登录页面。
9、简述 TCP 和 UDP的区别
TCP是传输控制协议UDP是用户数据表协议TCP长连接UDP无连接UDP程序结构较简单只需发送无须接收TCP可靠保证数据正确性、顺序性UDP不可靠可能丢数据TCP适用于少量数据UDP适用于大量数据传输TCP速度慢UDP速度快
10、什么是三次握手四次挥手
消息类型描述SYN这个消息是用来初始化和建立连接的 Synchronize Sequence NumbersACK帮助对方确认收到的SYN信息 Acknowledge characterSYN-ACK本地的SYN信息和较早的ACK数据包FIN用来断开连接的在客户机和服务器之间建立TCP连接时首先会发送的一个信号。客户端在接受到SYN消息时就会在自己的段内生成一个随机值X。 服务器收到SYN后打开客户端连接发送一个SYN-ACK作为答复。确认后设置为比接收到的序列号多一个即X1服务器为数据包选择的序列号是另一个随机数Y。 确认字符表示发来的数据已确认接收无误。最后客户端将ACK发送给服务器。序列号被设置为所接收的确认值即Y1。
举例 四次挥手
首先客户端应用程序决定要终止连接(这里服务端也可以选择断开连接)。这会使客户端将FIN发送到服务器并进入FIN_WAIT_1状态。当客户端处于FIN_WAIT_1状态时它会等待来自服务器的ACK响应。第二步当服务器收到FIN消息时服务器会立刻向客户端发送ACK确认消息。当客户端收到服务器发送的ACK响应后客户端就进入FIN_WAIT_2状态然后等待来自服务器的FIN 消息服务器发送ACK确认消息后一段时间(可以进行关闭后)会发送FIN消息给客户端告知客户端可以进行关闭。当客户端收到从服务端发送的FIN消息时客户端就会由FIN_WAIT_2状态变为TIME_WAIT状态。处于TIME_ WAIT 状态的客户端允许重新发送ACK到服务器为了防止信息丢失。客户端在TIME_ WAIT 状态下花费的时间取决于它的实现在等待一段时间后,连接关闭客户端上所有的资源. (包括端口号和缓冲区数据)都被释放。
举例 11、tcp 为什么要三次握手两次不行吗为什么
因为客户端和服务端都要确认连接①客户端请求连接服务端②针对客户端的请求确认应答并请求建立连接③针对服务端的请求确认应答建立连接
两次无法确保A能收到B的数据
十六、Git面试题
1、Git和SVN的区别 2、什么是Git
Git 是分布式版本控制系统DVCS。它可以跟踪文件的更改并允许你恢复到任何特定版本的更改。与 SVN 等其他版本控制系统VCS相比其分布式架构具有许多优势一个主要优点是它不依赖于中央服务器来存储项目文件的所有版本。每个开发人员都可以“克隆”我在图中用“Local repository”标注的存储库的副本并且在他的硬盘驱动器上具有项目的完整历史记录因此当服务器中断时你需要的所有恢复数据都在你队友的本地 Git 存储库中。还有一个中央云存储库开发人员可以向其提交更改并与其他团队成员进行共享如图所示所有协作者都在提交更改“远程存储库”。 3、Git的工作流程
十七、Maven面试题
1、什么是maven Maven主要服务于基于java平台的项目构建依赖管理和项目信息管理。maven项目对象模型(POM)可以通过一小段描述信息来管理项目的构建报告和文档的项目管理工具软件。它包含了一个项目对象模型一组标准集合一个项目生命周期一个依赖管理系统和用来运行定义在生命周期阶段中插件目标的逻辑。当使用Maven的时候你用一个明确定义的项目对象模型来描述你的项目然后Maven可以应用横切的逻辑这些逻辑来自于一组共享的或自定义的插件。 2、说说maven有什么优缺点
优点
简化了项目依赖管理易于上手对于新手来说了解几个常用命令即可满足日常工作便于与持续集成工具jenkins整合便于项目升级无论是项目本身还是项目使用的依赖maven有很多插件便于功能扩展比如生产站点自动发布版本等为什么使用Maven中的各点
缺点
Maven是一个庞大的构建系统学习难度大。很多都可以这样说入门容易[优点]但是精通难[缺点]Maven采用约定约定优于配置的策略虽然上手容易但是一旦出现问题难于调试中网络环境较差很多repository无法访问
3、讲一下maven的生命周期
Maven的 生命周期从我们的项目构建一直到项目发布的这个过程。 4、说说你熟悉哪些maven命令 5、