6.29:1、说一下jdk和jre的区别?
- JRE是java运行时环境,包含了java虚拟机,java基础类库。是使用java语言编写的程序运行所需要的软件环境,是提供给想运行java程序的用户使用的。
- JDK是java开发工具包,是程序员使用java语言编写java程序所需的开发工具包,是提供给程序员使用的。JDK包含了JRE,同时还包含了编译java源码的编译器javac,还包含了很多java程序调试和分析的工具:jconsole,jvisualvm等工具软件,还包含了java程序编写所需的文档和demo例子程序。
- 如果你需要运行java程序,只需安装JRE就可以了。如果你需要编写java程序,需要安装JDK。
6-29日每日一练解答的核心点:
1.介绍jdk(开发环境)和jre(运行环境)的概念
2.JDK包含JRE
3.JDK中包含开发工具包,编译器,调试和分析工具等
3.在项目部署时只需要jre即可,项目开发期间安装jdk
6.30:2、java的跨平台原理
- java的跨平台是通过java虚拟机来实现的
- Java是解释执行的,编译为中间码的编译器与平台无关,编译生成的中间码也与平台无关(一次编译,到处运行),中间码再由解释器解释执行,解释器是与平台相关的,也就是不同的平台需要不同的解释器.
- Java 解释器实际上就是特定的平台下的一个应用程序。只要实现了特定平台下的解释器程序,Java字节码就能通过解释器程序在该平台下运行,这是Java跨平台的根本。
- 同一个.class文件在不同的虚拟机 会得到不同的机器指令(Windows和Linux的机器指令不同),但是最终执行的结果却是相同的
7.1:3、java的基本数据类型,占用内存,byte,short的取值范围
这是8中基本类型的内存中占用字节数(取值范围是2的(字节数X8-1)次方)
1.整型
- 类型 存储需求 bit数 取值范围
- byte 1字节 1*8 -128~127
- short 2字节 2*8 -32768~32767
- int 4字节 4*8 (-2的31次方到2的31次方-1)
- long 8字节 8*8 (-2的63次方到2的63次方-1)
2.浮点型
- 类型 存储需求 bit数 备注
- float 4字节 4*8 float类型的数值有一个后缀F(例如:3.14F)
- double 8字节 8*8 没有后缀F的浮点数值(如3.14)默认为double类型
3.char类型
- 类型 存储需求 bit数
- char 2字节 2*8
4.boolean类型
- 类型 存储需求 bit数 取值范围
- boolean 1字节 1*8 false、true
7.2:4、a++和++a的区别
- a++:先运算后自增1;++a:先自增1后运算
- --同理
5、&和&&的区别
- Java中&&和&都是表示与的逻辑运算符,都表示逻辑运输符and,当两边的表达式都为true的时候,整个运算结果才为true,否则为false。
- &&的短路功能,当第一个表达式的值为false的时候,则不再计算第二个表达式;&则两个表达式都执行。
- &可以用作位运算符,当&两边的表达式不是Boolean类型的时候,&表示按位操作。
7.3:6、对比if和switch
- 从使用表面看
- if的分支只有两个,如果情况多种就得多个if-else
- swith可以同时支持任意多个分支
- 从适用范围
- if 语句适用范围比较广,只要是 boolean 表达式都可以用 if 判断;
- 而 switch 只能对byte、short、int、char、String进行数值比较
- 从设计上看
- (区间判断)if就是用来根据真假真正做分支用的,分支执行非此即彼,如果多个分支就得多重判断,无论前面的条件是否成立都得判断一遍,直至找到真正的true,就找到这个程序的分支流程而走开了
- (等值判断)swith则是一种通道开关设计,它的条件跟真假无关,无需逐一判断,它寻找的是一个通道入口,给定一个值立即就按它对应的入口执行后续流程而不是彻底走开,若要彻底走开还得特意break或者return一下
7、对比三种循环
循环说明 | for | while | do while |
结构 | for(循环次数【数组的length或集合的size】){ if(条件【true或false】){ 循环体; } } | while(条件【true或false】){ 循环体; } | do{ 循环体; }while(条件【true或false】); |
特点 | 先判断后执行 | 先判断后执行 | 先执行后判断,至少会执行一次 |
作用 | 循环次数确定 | 不确定循环次数 | 不确定循环次数 |
7.6:8、什么是类,什么是对象,类和对象的关系
对象:对象是人们要进行研究的任何事物,它不仅能表示具体的事物,还能表示抽象的规则、计划或事件
类:具有相同特性(数据元素)和行为(功能)的对象的抽象就是类
类与对象的关系就如模具和铸件的关系,类的实力化的结果就是对象,而对对象的抽象就是类,类描述了一组有相同特性(属性)和相同行为的对象。
9、什么是构造方法,什么是方法重载
什么是构造方法?
当新对象被创建的时候,构造方法就会被调用。每一个类都有构造方法,如果程序员没有给类提供构造方法,Java编译器会为这个类创建一个默认的构造方法。
方法重载是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数。
7.7:10、简述一下封装
- 封装,即隐藏对象的属性和实现细节,仅对外公开接口,控制程序中属性的读(get)和修改(set)的访问级别;将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。
11、简述static关键字的含义及用途,特点等
含义
- static表示“静态”的意思,可以用来修饰成员变量和成员方法(后续还会学习 静态代码块 和 静态内部类)。
用途
- static的主要作用在于创建独立于具体对象的域变量或者方法
特点:
- 被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。
- 静态成员 在类加载时加载并初始化。
- 无论一个类存在多少个对象 , 静态的属性, 永远在内存中只有一份( 可以理解为所有对象公用 )
- 在访问时: 静态不能访问非静态 , 非静态可以访问静态 !
- 静态修饰的方法被调用时有可能对象还未创建!
7-7日每日一练解答的核心点:
1.封装:将属性私有化,提供公有方法访问私有属性,提高了代码的安全性
2.static关键字,修改的属性或方法被提升到类级别的属性或方法,特点:可以直接通过类名.属性或类名.方法名调取
7.8:12、解释说明Java三大特性
封装、继承、多态
封装:就是把描述一个对象的属性和行为的代码封装在一个类中,有些属性是不希望公开的,或者说被其他对象访问的,所以我们使用private使其隐藏起来;类中提供了方法get、set等方法,可以操作这些被隐藏的属性,其他类可以通过调用这些方法,改变隐藏属性的值!
继承:在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,使用extends关键字实现继承;子类中可以加入若干新的内容,或修改原来的方法使之更适合特殊的需要,这就是继承。继承是子类自动共享父类数据和方法的机制,这是类之间的一种关系,提高了软件的可重用性和可扩展性。
多态:多态就是在声明时使用父类,在实现或调用时使用具体的子类,即父类引用指向子类对象;不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性,多态增强了软件的灵活性和扩展性。
13、抽象类和接口的区别
- 抽象类使用(extend)来被子类继承, 无法多继承。 接口使用(implements )来被子类实现, 可以多实现
- 抽象类中可以声明抽象方法,也可以写非抽象方法,接口只能声明抽象方法。
- 抽象类中的变量是普通变量,接口里定义的变量只能是公共的静态的常量。
- 抽象类中可以包含static方法 ,但是接口中不允许(静态方法不能被子类重写,因此接口中不能声明静态方法)
- 抽象类可以有构造方法,但是接口不能有
7.9:14、方法重写和方法重载的区别
区别点 | 方法重写 | 方法重载 |
范围 | 子类对父类 | 类本身 |
参数列表 | 一定不能修改 | 参数类型、个数或者顺序不同 |
返回类型 | 一定不能修改 | 可以修改 |
异常 | 可以减少或删除,一定不能跑出新的或者更广的异常 | 可以修改 |
访问 | 一定不能坐出更严格的限制(可以降低限制) | 可以修改 |
15、多态的表现形式有哪些
重载、重写、抽象类和接口。
7.10:16、介绍一下java中的异常处理机制
异常处理机制为:抛出异常,捕捉异常。
Java异常机制主要依赖于try、catch、finally、throw、throws五个关键字。
1.try:它里面放置可能引发异常的代码
2.catch:后面对应异常类型和一个代码块,用于表明该catch块用于处理这种类型的代码块,可以有多个catch块。如果异常发生在try语句,则会自动找到匹配的catch语句执行,如果没有在try语句中,则会将异 常抛出.
3.finally:在进行异常的处理之后,在异常的处理格式中还有一个finally语句,那么此语句将作为异常的统一出口,不管是否产生 了异常,最终都要执行此段代码。
4.throw:用于抛出一个实际的异常,可以单独作为语句使用,抛出一个具体的异常对象。
5.throws:用在方法签名中,用于声明该方法可能抛出的异常。
7月10日每日一练解答核心点:
1.什么是异常
2.异常的关键字
3.每个关键字的的含义以及作用
4.异常的分类
7.15:17、描述Java中的三大集合(接口,实现类,存值特点,存值原理等角度描述)
- Set集合。其主要实现类有HashSet、TreeSet。
- 存放对象的引用,不允许有重复对象。
- 1.HashSet(),调用对象的hashCode()方法,获得哈希码,然后再集合中计算存放对象的位置。通过比较哈希码与equals()方法来判别是否重复。所以,重载了equals()方法同时也要重载hashCode()方法。
- 2.TreeSet(),继承ShortedSet接口,能够对集合中对象排序。默认排序方式是自然排序,但该方式只能对实现了Comparable接口的对象排序,java中对Integer、Byte、Double、Character、String等数值型和字符型对象都实现了该接口。
- 如果有特殊排序,须重载该接口下的compareTo()方法或通过Comparator接口的实现类构造集合。
- List集合,其主要实现类有LinkedList、ArrayList,前者实现了链表结构,后者可代表大小可变的数组。
- List的特点是能够以线性方式储蓄对象,并允许存放重复对象。
- List能够利用Collections类的静态方法sort排序。
- sort(List list)自然排序;sort(List listm,Comparator codddmparator)客户化排序。
- List:线性集合接口,有序;ArrayList:动态数组[可变长度的动态数组];LinkedList:链表结构的集合
- Map集合,其主要实现类有
- HashMap、TreeMap。
- Map对值没有唯一性要求,对健要求唯一,如果加入已有的健,原有的值对象将被覆盖。
- HashMap类按照哈希算法来存取键对象,可以重载equals()、hashCode()方法来比较键,但是两者必须一致。
- TreeMap,可自然排序,也可通过传递Comparator的实现类构造TreeMap。
- Map:键值对存储结构的集合,无序
7月15日每日一练解答核心点:
1.集合类型:List,Set,Map
2.等级关系(Collection包含list,set,map独立)
3介绍三个集合的常用实现类,比如Arraylist,LinkedList
HashSet,HashMap等
4.存值特点:list-有序可重复,set-无序不可重复 ,map-key/value形式
5.数据结构:arrayList 顺序存储,Linkedlist 链表存储
6.底层实现:基于数组
7.面试常考:HashMap的实现原理
7.16:18、讲一下hashMap的实现原理
https://wwwblogs/yuanblog/p/4441017.html
HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
在java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。
总结:HashMap的实现原理:
- 利用key的hashCode重新hash计算出当前对象的元素在数组中的下标
- 存储时,如果出现hash值相同的key,此时有两种情况。(1)如果key相同,则覆盖原始值;(2)如果key不同(出现冲突),则将当前的key-value(键值对)放入链表中
- 获取时,直接找到hash值对应的下标,在进一步判断key是否相同,从而找到对应值。
- 理解了以上过程就不难明白HashMap是如何解决hash冲突的问题,核心就是使用了数组的存储方式,然后将冲突的key的对象放入链表中,一旦发现冲突就在链表中做进一步的对比。
初始容量为16,负载因子为0.75
7.17:19、Comparable和Comparator区别比较
- Comparable 是排序接口,仅仅只包括一个Comparable<T>函数xpareTo(y) 来“比较x和y的大小”。若返回“负数”,意味着“x比y小”;返回“零”,意味着“x等于y”;返回“正数”,意味着“x大于y”。
- Comparator 是比较器接口。仅仅只包括两个个函数int compare(T o1, T o2); boolean equals(Object obj);
- Comparable是排序接口;若一个类实现了Comparable接口,就意味着“该类支持排序”。
而Comparator是比较器;我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。
我们不难发现:Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。
20、HashMap和TreeMap的区别
- HashMap:基于哈希表实现,TreeMap:基于红黑树实现
- HashMap:适用于在Map中插入、删除和定位元素。
Treemap:适用于按自然顺序或自定义顺序遍历键(key)。
- HashMap不保证元素迭代顺序是按照插入时的顺序,Treemap会按照排序后的顺序迭代元素
7.20:21、说一下你了解的IO流体系
https://blog.csdn/iteye_15112/article/details/82580472
7.21:22、介绍一下序列化技术
序列化就是将对象状态转换为可保持或传输的格式的过程。与序列化相对的就是反序列化,他将流转换成对象。这两个过程结合起来,可以轻松地存储和传输数据。
要序列化的类,要实现Serializable接口,而这个接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个 ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。
7-21每日一练解答:
1.序列化反序列化的概念
2.实现方式和常用方法
3.不能序列化的情况:transient关键字修饰
7.22:23、介绍一下线程的生命周期
- Java线程具有五中基本状态
- 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
- 就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
- 运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
- 阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
- 1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
- 2.同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
- 3.其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
- 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
7.23:24、解释一下TCP协议的三次握手和四次挥手
理解及面试题链接:https://note.youdao/ynoteshare1/index.html?id=4b10010f9de5975d8689404a76286711&type=note
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
●第一次挥手:客户端向服务器发送一个FIN报文段,将设置seq为100和ack为120, ;此时,客户端进入FIN_ WAIT_ 1状态,这表示客户端没有数据要发送服务器了,请求关闭连接;
●第二次挥手:服务器收到了客户端发送的FIN报文段,向客户端回一-个ACK报文段,ack设置为101, seq设置为120;服务器进入了CLOSE _WAIT状态,客户端收到服务器返回的ACK报文后,进入FIN_ WAIT_ 2状态;
●第三次挥手:服务器会观察自己是否还有数据没有发送给客户端,如果有,先把数据发送给客户端,再发送FIN报文;如果没有,那么服务器直接发送FIN报文给客户端。请求关闭连接,同时服务器进入LAST_ ACK状态;
●第四次挥手:客户端收到服务器发送的FIN报文段,向服务器发送ACK报文段,将seq设置101,
将ack设置为121,然后客户端进入TIME_ WAIT状态;服务器收到客户端的ACK报文段以后,就关闭连接;此时,客户端等待2MSL后依然没有收到回复,则证明Server端已正常关闭,客户端也可以关闭连接了。
7.24:25、说一下TCP和UDP的区别
TCP与UDP区别总结:
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即UDP不保证可靠交付 3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;
UDP是面向报文的UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等) 4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信 5、TCP首部开销20字节;UDP的首部开销小,只有8个字节
6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
参考:https://wwwblogs/williamjie/p/9390164.html
7.27:26、列举css选择器有哪些
https://wwwblogs/isremya/p/12364741.html
1、元素选择器 标签名{ }
2、id选择器 #id属性值{ }
3、类选择器 ·class属性值{ }
4、选择器分组(并集选择器)语法:选择器1,选择器2,选择器n{ }
5、复合选择器(交集选择器)语法:选择器1 选择器2 选择器n{ }
6、通配选择器 语法:*{ }
7、后代元素选择器 语法:祖先元素 后代元素{ }
8、子元素选择器 语法:父元素>子元素
9、伪类选择器
- 伪类表示元素的一种特殊状态
- :hover 移入时元素的状态
- :visited 已被访问过后的元素的状态
- :active 被点击时元素的状态
10、 属性选择器 语法:
- [属性名]选取含有指定属性的元素
- [属性名=“属性值”]选取含指定属性值的元素
- [属性名^="属性值"] 选取属性值以指定内容开头的元素
- [属性名$="属性值"] 选取属性值以指定内容结尾的元素
- [属性名*="属性值"] 选取属性值包含指定内容的元素
11、兄弟元素选择器 语法:前一个+后一个(作用在后一个)
7.28:27、介绍一下反射(概念,工具类,使用场景等方向)
https://www.jianshu/p/9be58ee20dee
概念:
JAVA反射机制是在运行状态中,获取任意一个类的结构 , 创建对象 , 得到方法,执行方法 , 属性 !; 这种在运行状态动态获取信息以及动态调用对象方法的功能被称为java语言的反射机制。
工具类:Class,Constructor,Method,Field
getClass() 得到一个类的 类对象
forName(包名+类名): 得到一个类的 类对象
getConstructor(参数类型的class对象数组)获取指定的单个构造方法
newInstance(Object... para)把对应的对象创建出来
setAccessible(boolean flag)忽略访问权限检查
getMethod(String methodName , class.. clss)得一个方法
getField(String filedName)属性的名称, 获取一个属性对象
getAnnotation(注解类型.class)根据类型获取类/属性/方法的注解对象
每日一练回答要点:
1.反射概念:动态获取类中的信息,以及动态调用对象的方法的功能称为java的反射机制
2.反射的工具类:Class,Constructor,Method,Field
3.常用方法:如何获得Class,contructor如何创建对象,如何动态获取、调用方法。设置属性等
4.反射的使用场景:servlet,框架中应用较多,也可以自己基于反射来实现一些动态功能
7.30:28、解释一下线程通信模式
https://blog.csdn/zgz15515397650/article/details/78920305
说到线程之间通信方式:依据我的理解 主要是有两种吧
1.是通过共享变量,线程之间通过该变量进行协作通信;
2.通过队列(本质上也是线程间共享同一块内存)来实现消费者和生产者的模式来进行通信;
1.通过线程之间共享变量的方式
这个就有必要说下 wait(),notify(),以及notifyAll() 这三个方法
这三个方法都是属于Object的方法;所以所有类都可以继承这三方法;
wait()方法使得当前线程必须要等待,等到另外一个线程调用notify()或者notifyAll()方法。
notify()方法会唤醒一个等待当前对象的锁的线程。而notifyAll()顾名思义;就是唤醒所有在等待中的方法;
wait()和notify()方法要求在调用时线程已经获得了对象的锁,因此对这两个方法的调用需要放在synchronized方法或synchronized块中。
每日一练回答要点:
1.线程通信的概念(为了实现线程之间的信息交互)
2.通信的方式:wait(),notify(),notifyAll()三个方法实现
注意:这三个方法是Object的方法,而并非是Thread的
3.线程通信的经典模式:生产者消费者模式,大家下去以后一定要看一下,并能够表述生产者消费者模式
4.注意一点:这三个方法一定要在同步方法中实现
7.31:29、什么是值传递和引用传递
- 值传递传递是对基本数据类型而言的,传递的是该变量的一个副本,改变副本不影响原变量.
- 引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本,并不是原对象的副本。 所以对引用对象进行操作会同时改变原对象. 一般认为,java内的传递都是值传递.
每日一练回答要点:
考的点是基本数据类型和引用数据类型的作为参数时,值传递问题。
如果参数是基本类型,传递的是基本类型的字面量值的拷贝。
如果参数是引用类型,传递的是该参量所引用的对象在堆中地址值的拷贝。
8.3:30、synchronized 和 Lock 有什么区别?
- 实现层面不一样。synchronized 是 Java 关键字,JVM层面 实现加锁和释放锁;Lock 是一个接口,在代码层面实现加锁和释放锁
- 是否自动释放锁。synchronized 在线程代码执行完或出现异常时自动释放锁;Lock 不会自动释放锁,需要再 finally {} 代码块显式地中释放锁
- 是否一直等待。synchronized 会导致线程拿不到锁一直等待;Lock 可以设置尝试获取锁或者获取锁失败一定时间超时
- 获取锁成功是否可知。synchronized 无法得知是否获取锁成功;Lock 可以通过 tryLock 获得加锁是否成功
- 功能复杂性。synchronized 加锁可重入、不可中断、非公平;Lock 可重入、可判断、可公平和不公平、细分读写锁提高效率
每日一练回答要点:
1.相同点:都是java中获取线程锁的方式
2.不同点:
2.1 定义不同,synchronized是关键字,lock是对象
2.2 获得锁的方式不同
2.3 控制的元素不同,synchronized控制代码块或方法,lock锁代码
2.4 加锁和解锁方式不同
2.5 获取锁失败时,处理方式不同
8.4:31、JVM如何加载字节码文件?
http://note.youdao/noteshare?id=b5744b3767585d08173facccf57248d4
每日一练答题核心点(8月4日)
1.类加载机制:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可被虚拟机直接使用的Java类型
2.加载过程:
2.1 加载:通过类名进行加载,
2.2 链接(验证,准备,解析):文件格式验证,元数据验证,字节码验证,符号引用验证。为变量分配内存或初始值等
2.3 初始化:初始化用于执行Java类的构造方法
8.5:32、怎么防止死锁?
https://wwwblogs/bopo/p/9228834.html
我们可以通过破坏死锁产生的4个必要条件来 预防死锁,由于资源互斥是资源使用的固有特性是无法改变的。
1.破坏“不可剥夺”条件:一个进程不能获得所需要的全部资源时便处于等待状态,等待期间他占有的资源将被隐式的释放重新加入到 系统的资源列表中,可以被其他的进程使用,而等待的进程只有重新获得自己原有的资源以及新申请的资源才可以重新启动,执行。
2.破坏”请求与保持条件“:第一种方法静态分配即每个进程在开始执行时就申请他所需要的全部资源。第二种是动态分配即每个进程在申请所需要的资源时他本身不占用系统资源。
3.破坏“循环等待”条件:采用资源有序分配。其基本思想是将系统中的所有资源顺序编号,将紧缺的,稀少的采用较大的编号,在申请资源时必须按照编号的顺序进行,一个进程只有获得较小编号的进程才能申请较大编号的进程。
每日一练答题核心点(8月5日):
1.说明死锁的条件:
1.1 互斥:所分配的资源不允许其他进程访问,其他线程等待
1.2 请求和保持条件:对其他请求阻塞,自身资源不释放
1.3 不可剥夺条件:未完成使用之前,不可以被剥夺
1.4 环路等待条件:发生死锁后,若干进程之间形成一种头尾相接的循环等待资源
2 .解决方案:针对死锁形成的原因,防止上诉四个条件的的发生,可以在系统设计,进程调度等方面注意如何防止四个条件成立,如何确定资源的合理分配算法,避免进程永久占据系统资源
8.6:33、Collection和Collections的区别
https://blog.csdn/sfhinsc/article/details/84060783
1、java.util.Collection 是一个集合框架的父接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。它的意义是为各种具体的集合提供了最大化的统一操作方式。
2、java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。
34、final, finally, finalize的区别
https://wwwblogs/smart-hwt/p/8257330.html
https://wwwblogs/ktao/p/8586966.html
1)final 是 java中的关键字,修饰符。用于声明变量、方法和类,分别表示变量只能赋值一次不可变、方法不可覆盖、类不可被继承(不能再派生出新的子类)
2)finally作为异常处理的一部分,它只能用在try/catch语句中,并且附带着一个语句块,表示这段语句最终一定被执行,经常被用在需要释放资源的情况下。
3)finalize是Object类中的一个方法,在垃圾收集器执行的时候会调用被回收对象的finalize()方法,可以覆盖此方法来实现对其他资源的回收,例如关闭文件等。需要注意的是,一旦垃圾回收器准备好释放对象占用的空间,将首先调用其finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
每日一练核心点(8月6日):
1.collections是集合的工具类,collection是list,set的父接口,两者没有直接关系,只是长得像。
2.final 关键字,修饰的变量是常量,修饰的方法不能被重写,修饰的类不能被继承。
finally 异常处理的关键字,修饰的代码块表示无论是否有异常都要执行
finalize是gc机制中的一个方法,用来对对象回收的最后确认
8.7:35、斐波那契数列 递归实现斐波那契
思维题::
有一对兔子,从出生后第3个月起每个月都生- -对兔子,小兔子长到第三个月后每个又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?
要求:用代码的方式解决上述问题
我的答案:java递归实现,没找到规律,效率极低
public class Demo {
public static void main(String[] args) {
int x = 5;//x个月>3
int sum = 1;// 起始一对兔子
//出生第三个月起每个月生一对兔子,即每满两个月生一对兔子
// 第一对兔子 第3月开始生 共生了 x-2对 即(x-2)*2 只
// 第二对兔子 第5月开始生 共生了 x-2-2对
// 第三对兔子 第6月开始生 共生了 x-2-2-1对
sum = life(x,sum);
System.out.println("第"+x+"月一共有"+sum+"对兔子");
}
/**
*
* @param x 该兔子出生后的第几月
* @param sum 该兔子出生后的兔子总对数
* @return 每个月该兔子本身及后代总对数
*/
static public int life(int x,int sum){
if(x>=3 && sum >0){//第三个月开始生
for(int i=1;i<=x-2;i++){
sum++;
System.out.println("第"+sum+"对兔子");
sum = life(x-2-i+1,sum);//小兔子开始生育
}
}
return sum;
}
标答:递归实现斐波那契
public class demo {
public static void main(String args[]) {
System.out.println(rabbit(Integer.parseInt(new Scanner(System.in).next())));
}
private static int rabbit(int n) {
if (n == 1 || n == 2) {
return 1;
} else {
return rabbit(n - 1) + rabbit(n - 2);
}
}
}
其余答案:数组实现
8.10:36、jq和js的区别和联系
https://wwwblogs/wangtaobiu/p/10241344.html
JavaScript 是通过标签插入到HTML页面,可由所有的现代浏览器执行的一种轻量级的编程语言。
而jQuery是一个基于js编写的框架,实质上还是js,封装了我们开发过程中常用的文档遍历和操作,事件处理,动画和Ajax,方便我们调用,提高开发效率。
1.jQuery 是一个 JavaScript 库;
2.jQuery 极大地简化了 JavaScript 编程;
3.jQuery 使JavaScript更好用;
4.jquery就是要用更少的代码,漂亮的完成更多的功能
37、介绍一种你学过的前端框架,并进行描述
Bootstrap 是一个用于快速开发 Web 应用程序和网站的前端框架。Bootstrap 是基于 HTML、CSS、JAVASCRIPT 的。
https://www.runoob/bootstrap/bootstrap-intro.html
https://wwwblogs/zhaopanpan/articles/8939635.html特点;
移动设备优先:自 Bootstrap 3 起,框架包含了贯穿于整个库的移动设备优先的样式。
浏览器支持:所有的主流浏览器都支持 Bootstrap。
容易上手:只要您具备 HTML 和 CSS 的基础知识,您就可以开始学习 Bootstrap。
响应式设计:Bootstrap 的响应式 CSS 能够自适应于台式机、平板电脑和手机。更多有关响应式设计的内容详见 Bootstrap 响应式设计。它为开发人员创建接口提供了一个简洁统一的解决方案。
它包含了功能强大的内置组件,易于定制。
它还提供了基于 Web 的定制。
它是开源的。
Bootstrap 包的内容:
基本结构:Bootstrap 提供了一个带有网格系统、链接样式、背景的基本结构。这将在 Bootstrap 基本结构 部分详细讲解。
CSS:Bootstrap 自带以下特性:全局的 CSS 设置、定义基本的 HTML 元素样式、可扩展的class,以及一个先进的网格系统。这将在 Bootstrap CSS 部分详细讲解。
组件:Bootstrap 包含了十几个可重用的组件,用于创建图像、下拉菜单、导航、警告框、弹出框等等。这将在 布局组件部分详细讲解。
JavaScript 插件:Bootstrap 包含了十几个自定义的 jQuery 插件。您可以直接包含所有的插件,也可以逐个包含这些插件。这将在 Bootstrap 插件 部分详细讲解。
定制:您可以定制 Bootstrap 的组件、LESS 变量和 jQuery 插件来得到您自己的版本。
8.11:38、SQL语法规则
1.增加:insert into 表名(列名) values (列值)
- 修改: update 表名 set 列名=列值,列名2=列值2 where 限定条件
- 删除: delete from 表名 where 限定条件
2.两表内联:
- (1)select 列名 from 表1 inner join 表2 on 表1.列名=表2.列名
- (2)select 列名 from 表1,表2 where 表1.列名=表2.列名
3.查询:
select 列名 from 表名 where 限定条件 group by 分组列名 having 分组后的限定条件 order by 排序的列名 asc/desc limit 开始位置,显示条数
8.12:39、JDBC连接数据库的步骤
状态通道:
1.导入jar包
2.加载驱动:Class.forname("com.mysql.jdbc.Driver");
3.通过驱动管理获得连接:Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=utf-8","数据库账号","数据库密码");
4.通过连接创建Sql对象
Statement state = conn.creatStatement();
5.执行SQL语句
state.execute("sql语句");
6.关闭连接
state.close();
conn.close();预状态通道
1.导入jar包
2.加载驱动:Class.forname("com.mysql.jdbc.Driver");
3.通过驱动管理获取连接:Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/数据库名称?useUnicode=true&characterEcoding=utf-8","数据库账号","数据库密码");
4.通过连接创建SQL对象并预编译sql语句:PraperStatement state=conn.creatPraperStatement("sql语句");
5.执行SQL:int i = state.excuteUpdate();|| ResultSet rs = state.excuteQuery();
6.关闭连接
rs.close();state.close();conn.close();
8.13:40、有1、2、3、4个数字,能组成多少个互不相同且无重复的三位数,分别是多少?
public class Demo {
public static void main(String[] args) {
int sum = 0;//三位数个数
int count = 0;//计数器
for (int i = 1; i <=4 ; i++) {
for (int j = 1; j <=4; j++) {
if(j != i){
for (int k = 1; k <= 4; k++) {
if(k != i && k != j){
System.out.println(i*100+j*10+k);
sum++;
}
count++;
}
}else{
count++;
}
}
}
System.out.println("总共"+sum+"个三位数");
System.out.println("运行"+count+"圈");
}
}
8.14:41、有两根不均匀分布的香,每根香烧完的时间是一个小时,你能用什么方法来确定一段15分钟的时间?
答:把两根香同时点起来,第一支香两头点着,另一支香只烧一头,等第一支香烧完花了半个小时,第二支香还剩半个小时,把第二支香另一头点燃,另一头从燃起到熄灭的时间就是15分!
8.17:42、一架飞机绕地球半圈需要一桶油,一架只能装一桶油,飞机之间可以互相加油,现在要保证一架飞机能绕地球一圈,至少需要多少驾飞机?要求其它飞机不能降落,要保证能返航,速度可以不考虑,在加油的过程可以瞬间加满油,可以返航加油
答案:3架。
https://blog.csdn/Athenaer/article/details/8612536
8.18:43、说一下servlet生命周期
https://www.runoob/servlet/servlet-life-cycle.html
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
- Servlet 通过调用 init () 方法进行初始化。
- Servlet 调用 service() 方法来处理客户端的请求。
- Servlet 通过调用 destroy() 方法终止(结束)。
- 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
8.19:44、猴子吃桃问题
8.20:45、介绍一下JSP的九大内置对象以及常用方法
JSP中一共预先定义了9个这样的对象,分别为:request、response、session、application、out、
pagecontext、config、page、exception
https://wwwblogs/liuyangv/p/8059848.html
8.21:46、驴吃萝卜问题
想要商人卖得最多du,就等于是让驴吃最少,而要驴吃最少,就等于驴走了最短的路程。
不管驴驮多驮少,每走1公里都是吃1根胡萝卜,所以,尽量让驴背上的胡萝卜保持最多,最后剩下的胡萝卜也就最多;而让驴驮最多就需要每段出发时驴背上都满载(1000根),这就要求每个分段的胡萝卜数量都必须是1000的整倍数——胡萝卜3000根,一次背1000根,3000除以1000等于3,因此需要把路分成3段,中间有两个停靠点。
总路程是1000公里,总共3000根,让驴每次都驮最大值,那就是1000根。需要先将3000根放在1000公里的某个临时点,假定这个临时点位A,驴到A的位置,每次驮1000根,来回要五次。5*距离=1000根。得出A的位置是200公里处。此时还剩2000根。同理,将2000根移动到A和终点之间的一个位置,假定这个位置是B。A到B的位置来回走三次即可移动。3*距离=1000根。距离≈333。到B位置时剩余1000根,行走了200+333=533公里,剩余距离一趟走完,1000-533=467公里,走完467公里后,剩余533根胡萝卜
9月2日:47、volatile干什么的?原理是什么?
推荐:https://note.youdao/ynoteshare1/index.html?id=4f2e05fe5d6b2598c5d0c672872f0c2b&type=note
volatile作用:
volatile 是一个类型修饰符。volatile 的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略
volatile原理:
Java语言提供了一种稍弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程。当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。
在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比sychronized关键字更轻量级的同步机制。
当对非 volatile 变量进行读写的时候,每个线程先从内存拷贝变量到CPU缓存中。如果计算机有多个CPU,每个线程可能在不同的CPU上被处理,这意味着每个线程可以拷贝到不同的 CPU cache 中。
而声明变量是 volatile 的,JVM 保证了每次读变量都从内存中读,跳过 CPU cache 这一步。
volatile 性能:
volatile 的读性能消耗与普通变量几乎相同,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。
当一个变量定义为 volatile 之后,将具备两种特性:
1.保证此变量对所有的线程的可见性,这里的“可见性”,如本文开头所述,当一个线程修改了这个变量的值,volatile 保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。但普通变量做不到这点,普通变量的值在线程间传递均需要通过主内存(详见:Java内存模型)来完成。2.禁止指令重排序优化。有volatile修饰的变量,赋值后多执行了一个“load addl $0x0, (%esp)”操作,这个操作相当于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前的位置),只有一个CPU访问内存时,并不需要内存屏障;(什么是指令重排序:是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理)。
9月3日:48、SQL语句优化有哪些方法?
参考网址:https://wwwblogs/Little-Li/p/8031295.html
9月4日:49、http和https的区别?
参考网址:https://blog.csdn/qq_38289815/article/details/80969419
1、HTTPS 协议需要到 CA (Certificate Authority,证书颁发机构)申请证书,一般免费证书较少,因而需要一定费用。(以前网易官网是http,而网易邮箱是 https 。)
2、HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议。
3、HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、HTTP 的连接很简单,是无状态的。HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。(无状态的意思是其数据包的发送、传输和接收都是相互独立的。无连接的意思是指通信双方都不长久的维持对方的任何信息。)
9月7日:50、sql语句中count(*),count(1),count(id)区别详解
参考网址:https://blog.csdn/Jame_s/article/details/102926383
9.14-9.19周测题:
1.JVM内存分哪几个区,每个区的作用是什么
java 虚拟机主要分为以下五个区:
方法区:
- 有时候也称为永久代,在该区内很少发生垃圾回收,但是并不代表不发生 GC,在这里进行的 GC 主要是对方法区里的常量池和对类型的卸载
- 方法区主要用来存储已被虚拟机加载的类的信息、常量、静态变量和即时编译器编译后的代码等数据。
- 该区域是被线程共享的。
- 方法区里有一个运行时常量池,用于存放静态编译产生的字面量和符号引用。该常量池具有动态性,也就是说常量并不一定是编译时确定,运行时生成的常量也会存在这个常量池中。
虚拟机栈:
- 虚拟机栈也就是我们平常所称的栈内存,它为 java 方法服务,每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接和方法出口等信息。
- 虚拟机栈是线程私有的,它的生命周期与线程相同。
- 局部变量表里存储的是基本数据类型、returnAddress 类型(指向一条字节码指令的地址)和对象引用,这个对象引用有可能是指向对象起始地址的一个指针,也有可能是代表对象的句柄或者与对象相关联的位置。局部变量所需的内存空间在编译器间确定
- 操作数栈的作用主要用来存储运算结果以及运算的操作数,它不同于局部变量表通过索引来访问,而是压栈和出栈的方式
- 每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接.动态链接就是将常量池中的符号引用在运行期转化为直接引用。
本地方法栈
- 本地方法栈和虚拟机栈类似,只不过本地方法栈为 Native 方法服务。
堆
- java 堆是所有线程所共享的一块内存,在虚拟机启动时创建,几乎所有的对象实例都在这里创建,因此该区域经常发生垃圾回收操作。
程序计数器
- 内存空间小,字节码解释器工作时通过改变这个计数值可以选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理和线程恢复等功能都需要依赖这个计数器完成。该内存区域是唯一一个 java 虚拟机规范没有规定任何 OOM 情况的区域。
2.创建线程有哪几种方式?分别有什么不同?
参考网址:https://wwwblogs/felixzh/p/6036074.html
Java多线程实现方式主要有四种:
- 继承Thread类实现
- 实现Runnable接口
- 实现Callable接口通过FutureTask包装器来创建Thread线程
- 使用ExecutorService、Callable、Future实现有返回结果的多线程。
注:一般推荐采用实现接口的方式来创建多线程
区别:
- 继承Thread类不能再继承其它的父类,由java单继承特性决定,而实现Runnable接口和实现Callable接口避免多继承局限
- 继承Thread类和实现Runnable接口无返回值,而实现Callable接口和使用ExecutorService、Callable、Future实现的多线程有返回值
- 通过Executor 的工具类可以创建三种类型的普通线程池
- 实现Runnable()可以更好的体现共享的概念
3.说一下设计模式的六大原则,分别代表什么?
参考网址:https://wwwblogs/toutou/p/4870926.html#_label6
- 开闭原则(Open Closed Principle,OCP)
- 一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。模块应尽量在不修改原(是“原”,指原来的代码)代码的情况下进行扩展。
- 里氏代换原则(Liskov Substitution Principle,LSP)
- 派生类(子类)对象能够替换其基类(父类)对象被调用
- 依赖倒转原则(Dependency Inversion Principle,DIP)
- 是程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
- 接口隔离原则(Interface Segregation Principle,ISP)
- 客户端不应该依赖它不需要的接口,类间的依赖关系应该建立在最小的接口上
- 合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP)
- 经常又叫做合成复用原则。就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用已有功能的目的。它的设计原则是:要尽量使用合成/聚合,尽量不要使用继承。
- 最小知识原则(Principle of Least Knowledge,PLK,也叫迪米特法则)
- 一个软件实体应当尽可能少的与其他实体发生相互作用。每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。迪米特法则的初衷在于降低类之间的耦合。由于每个类尽量减少对其他类的依赖,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或很少有)依赖关系。迪米特法则不希望类之间建立直接的联系。如果真的有需要建立联系,也希望能通过它的友元类来转达。因此,应用迪米特法则有可能造成的一个后果就是:系统中存在大量的中介类,这些类之所以存在完全是为了传递类之间的相互调用关系——这在一定程度上增加了系统的复杂度。
开闭原则具有理想主义的色彩,它是面向对象设计的终极目标。其他几条,则可以看做是开闭原则的实现方法。 设计模式就是实现了这些原则,从而达到了代码复用、增加可维护性的目的。
4.string、stringbuilder、stringbuffer区别
参考网址:https://blog.csdn/weixin_41101173/article/details/79677982
三者的区别:
(1)字符修改上的区别(主要)
- String:不可变字符串;
- StringBuffer:可变字符串、效率低、线程安全;
- StringBuilder:可变字符序列、效率高、线程不安全;
(2)初始化上的区别,String可以空赋值,后者不行,报错
小结:
- 如果要操作少量的数据用 String;
- 多线程操作字符串缓冲区下操作大量数据 StringBuffer;
- 单线程操作字符串缓冲区下操作大量数据 StringBuilder(推荐使用)。
5.描述HashMap底层原理?
https://wwwblogs/fenjyang/p/11486403.html
https://wwwblogs/little-fly/p/7344285.html
- 首先有一个每个元素都是链表(可能表述不准确)的数组,
- 当添加一个元素(key-value)时,就首先计算元素key的hash值,以此确定插入数组中的位置,
- 但是可能存在同一hash值的元素已经被放在数组同一位置了,这时就添加到同一hash值的元素的后面,他们在数组的同一位置,但是形成了链表,同一各链表上的Hash值是相同的,所以说数组存放的是链表。
- 而当链表长度太长时(链表长度超过阈值(8)时),链表就转换为红黑树,链表长度小于6时红黑树转换为链表,这样大大提高了查找的效率。
- 当链表数组的容量超过初始容量的0.75(加载因子)时,再散列将链表数组扩大2倍,把原链表数组的搬移到新的数组中
6.描述Servlet生命周期
https://www.runoob/servlet/servlet-life-cycle.html
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
Servlet 通过调用 init () 方法进行初始化。
Servlet 调用 service() 方法来处理客户端的请求。
Servlet 通过调用 destroy() 方法终止(结束)。
最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
7.抽象类和接口的区别
https://jingyan.baidu/article/ceb9fb10703f7f8cac2ba05e.html
- 抽象类要被子类继承,接口要被类实现。
- 接口只能做方法声明,抽象类中可以作方法声明,也可以做方法实现。
- 接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
- 接口是设计的结果,抽象类是重构的结果。
- 抽象类和接口都是用来抽象具体对象的,但是接口的抽象级别最高。
- 接口只能有抽象方法和不可变常量,抽象类可以有具体的方法和属性。
- 接口主要用来抽象功能,抽象类主要用来抽象类别。
8.JDBC操作数据库的基本步骤,写出过程
https://wwwblogs/xuxinstyle/p/9128869.html
- 加载数据库驱动
- 获得数据库连接
- 创建数据库操作对象
- 定义操作的SQL语句并执行
- 获取并操作结果集
- 关机对象,回收数据库资源(关闭结果集-->关闭数据库操作对象-->关闭连接)
9.get和post请求的区别?
https://wwwblogs/logsharing/p/8448446.html
- GET在浏览器回退时是无害的,而POST会再次提交请求。
- GET产生的URL地址可以被Bookmark,而POST不可以。
- GET请求会被浏览器主动cache,而POST不会,除非手动设置。
- GET请求只能进行url编码,而POST支持多种编码方式。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET请求在URL中传送的参数是有长度限制的,而POST么有。
- 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- GET参数通过URL传递,POST放在Request body中。
- GET和POST还有一个重大区别,简单的说:
- GET产生一个TCP数据包;POST产生两个TCP数据包。
10.Session和Cookie的区别
https://wwwblogs/8023-CHD/p/11067141.html
- cookie数据存放在客户的浏览器上,session数据放在服务器上。
- cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。
- session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。
- 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
- 可以考虑将登陆信息等重要信息存放为session,其他信息如果需要保留,可以放在cookie中。
11.描述一下三次握手四次挥手
同7.23
理解及面试题链接:https://note.youdao/ynoteshare1/index.html?id=4b10010f9de5975d8689404a76286711&type=note
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
●第一次挥手:客户端向服务器发送一个FIN报文段,将设置seq为100和ack为120, ;此时,客户端进入FIN_ WAIT_ 1状态,这表示客户端没有数据要发送服务器了,请求关闭连接;
●第二次挥手:服务器收到了客户端发送的FIN报文段,向客户端回一-个ACK报文段,ack设置为101, seq设置为120;服务器进入了CLOSE _WAIT状态,客户端收到服务器返回的ACK报文后,进入FIN_ WAIT_ 2状态;
●第三次挥手:服务器会观察自己是否还有数据没有发送给客户端,如果有,先把数据发送给客户端,再发送FIN报文;如果没有,那么服务器直接发送FIN报文给客户端。请求关闭连接,同时服务器进入LAST_ ACK状态;
●第四次挥手:客户端收到服务器发送的FIN报文段,向服务器发送ACK报文段,将seq设置101,
将ack设置为121,然后客户端进入TIME_ WAIT状态;服务器收到客户端的ACK报文段以后,就关闭连接;此时,客户端等待2MSL后依然没有收到回复,则证明Server端已正常关闭,客户端也可以关闭连接了。
12.用递归写出来阶乘
public static void main(String[] args) { System.out.println(factoria(5)); } public static int factoria(int num) { if(num==0||num==1){ return 1; }else if(num > 1){ return num*factoria(num-1); }else { System.out.println("请输入正整数"); return 0; } }
13.默写二分查找
public static void main(String[] args) { int[] nums = {1,2,3,4,5,6,7}; int num = 4; find(nums,num); } public static void find(int[] nums,int num) { int min = 0; int max = nums.length-1; int mid = (min+max)/2; int index= -1; //都相等的数组 if (nums[min] == nums[max] || nums[min] == num){ index = 0; } //数组递增 while(nums[min] < nums[max]){ //不在范围内 if(nums[min] > num || nums[max] < num){ break; } if(nums[mid] > num){ max = mid; mid = (min+max)/2; }else if(nums[mid] < num) { min = mid; mid = (min+max)/2; }else { index = mid; break; } if(min == max){ break; } } //数组递减 while(nums[min] > nums[max]){ //不在范围内 if(nums[min] < num || nums[max] > num){ break; } if(nums[mid] > num){ min = mid; mid = (min+max)/2; }else if(nums[mid] < num) { max = mid; mid = (min+max)/2; }else { index = mid; break; } if(min == max){ break; } } if(index == -1){ System.out.println("没有目标数字"); }else { System.out.println("查找的数字下标为"+index); } }
14.默写单例模式的懒汉式和饿汉式
https://blog.csdn/qq_37904799/article/details/81807954
//饿汉式 public class ESingle{ //一来就自己创建一个实例 private static ESingle eSingle = new ESingle(); private ESingle(){}; public ESingle getESingle(){ return eSingle; } } //懒汉式 public class LSingle{ private static LSingle lSingle = null; private LSingle(){}; public LSingle getLSingle(){ //需要的时候创建一个实例 if(lSingle == null){ lSingle = new LSingle(); } return lSingle; } }
15.海滩上有一堆桃子,五只猴子来分。第一只猴子把这堆桃子平均分为五份,多了一个,这只猴子把多的一个扔入海中,拿走了一份。第二只猴子把剩下的桃子又平均分成五份,又多了一个,它同样把多的一个扔入海中,拿走了一份,第三、第四、第五只猴子都是这样的,问海滩上原来最少有多少个桃子?
public static void main(String[] args) { num(5); } //总共n只猴子 public static void num(int n){ //最少的情况沙滩上还剩4份,每份一个 int sum = 1; //第五只猴子拿之前剩1*5+1 for (int i = 0; i < n; i++) { sum = sum*5+1; } System.out.println("海滩上原来最少有"+sum+"个桃子"); }
9.21-9.27周测题
1.何为范式,有几种,试列举并简要描述?
参考:https://blog.csdn/wenco1/article/details/88077279
范式是“符合某一种级别的关系模式的集合,表示一个关系内部各属性之间的联系的合理化程度”。
数据库范式也分为1NF,2NF,3NF,BCNF,4NF,5NF。一般在我们设计关系型数据库的时候,最多考虑到BCNF就够。符合高一级范式的设计,必定符合低一级范式,例如符合2NF的关系模式,必定符合1NF。
- 1NF的定义为:符合1NF的关系中的每个属性都不可再分。
- 2NF在1NF的基础之上,消除了非主属性对于码的部分函数依赖。
- 3NF在2NF的基础之上,消除了非主属性对于码的传递函数依赖。
- BCNF在3NF 的基础上消除主属性对于码的部分与传递函数依赖。
2.简述一下Spring框架?
https://blog.csdn/qq_42963930/article/details/101514105
spring是一个容器 , 实际上spring是203年兴起的一个轻量级的java开放框架, 他是为了解决管理对象的复杂性二创建的, spring的两大核心和 IOC (控制反转)和 AOP (面向切面编程) 是可以在JavaSE //EE 中使用的轻量级开源框架。
spring框架是一个半成品的框架 , 主要作用就是代码的 “解耦合” ,让代码中对象与对象之间 (模块与模块之间的) 关系不再使用代码关联 ,spring框架根据代码的特点,不用开发人员自己创建对象 , 而是统一交给spring容器来进行统一管理 , 而vAOP使得系统服务得到最大复用,有spring容器统一完成 “织入”。
(织入 : 把切面aspect连接到其它的应用程序类型或者对象上 , 并创建一个被通知的advised)的对象叫做织入)
优点:
- 1、轻量
- Spring 框架使用的 jar 都比较小,一般在 1M 以下或者几百 kb。Spring 核心功能的所需的 jar 总共在 3M 左右。Spring 框架运行占用的资源少,运行效率高。不依赖其他 jar
- 2、针对接口编程 代码解耦合
- spring提供了IOC控制反转 , 有spring创建对象和管理对象
- 3、AOP面向切面编程
- 在spring中 , 开发人员可以从繁杂的事物管理代码中解脱出来 , 通过声明式灵活地进行事务的管理, 大大提高开发效率 , 并且对于后期维护也方便很多
- 4.方便集成各种优秀框架
- spring不排斥各种优秀的开源框架 ,可以把spring框架看做是一个插线板 , 其它框架看作是插头 , 如果你的项目中需要使用到 直接就可以插入到这个插板上 , 不需要拔出即可 。
3.Redis 为什么是单线程的?
https://www.php/redis/453410.html
Redis 为什么是单线程的
- 单线程不需要各种锁的性能消耗;
- 单线程多进程集群方案;
- 采用单线程避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗CPU。
简单分析:
Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。因为单线程容易实现,并且CPU不会成为瓶颈,那么redis就顺理成章地采用单线程的方案了。
详细原因介绍:
- 不需要各种锁的性能消耗
- Redis的数据结构并不全是简单的Key-Value,还有list,hash等复杂的结构,这些结构有可能会进行很细粒度的操作,比如在很长的列表后面添加一个元素,在hash当中添加或者删除一个对象。这些操作可能就需要加非常多的锁,导致的结果是同步开销大大增加。
- 总之,在单线程的情况下,就不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗。
- 单线程多进程集群方案
- 单线程的威力实际上非常强大,每核心效率也非常高,多线程自然是可以比单线程有更高的性能上限,但是在今天的计算环境中,即使是单机多线程的上限也往往不能满足需要了,需要进一步摸索的是多服务器集群化的方案,这些方案中多线程的技术照样是用不上的。
- CPU消耗
- 采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU。但是如果CPU成为Redis瓶颈,或者不想让服务器其他CUP核闲置,那怎么办?
- 可以考虑多起几个Redis进程,Redis是key-value数据库,不是关系数据库,数据之间没有约束。只要客户端分清哪些key放在哪个Redis进程上就可以了。
4. redis的数据类型,以及每种数据类型的使用场景
https://wwwblogs/xianchonyigeyi/p/11497894.html
一共五种
(一)String
这个其实没啥好说的,最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存。
(二)list
使用List的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。
(三)hash
这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。博主在做单点登录的时候,就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,能很好的模拟出类似session的效果。
(四)set
因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能。为什么不用JVM自带的Set进行去重?因为我们的系统一般都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个做一个全局去重,再起一个公共服务,太麻烦了。
另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。
(五)sorted set
sorted set多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP N操作。
5.this和super的区别?
一、指代不同
- super:是当前对象里面的父对象的引用。
- this:指的是当前对象的引用。
二、调用函数不同
- super:调用基类中的某一个构造函数(应该为构造函数中的第一条语句) 。
- this:调用本类中另一种形成的构造函数(应该为构造函数中的第一条语句)。
三、引用对象不同
- super:引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)。
- this:代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)。
6.线程的生命周期的六种状态分别是什么,对各个状态进行说明?
线程状态。 线程可以处于以下状态之一:
NEW 尚未启动的线程处于此状态。线程刚被创建,但尚未启动。
RUNNABLE 在Java虚拟机中执行的线程处于此状态。线程正在JVM中执行,有可能在等待操作系统中的其他资源,比如处理器。
BLOCKED 被阻塞等待监视器锁定的线程处于此状态(即在排队)。处于受阻塞状态的某一线程正在等待监视器锁,以便进入一个同步的块/方法,或者在调用 Object.wait 之后再次进入同步的块/方法。在Thread Dump日志中通常显为
java.lang.Thread.State: BLOCKED (on object monitor) 。WAITING 无限期等待另一个线程执行特定操作的线程处于此状态,线程因为调用下面的方法之一而处于等待状态:
- 不带超时的 Object.wait 方法,日志中显示为 java.lang.Thread.State: WAITING (on object monitor)
- 不带超时的 Thread.join 方法
- LockSupport.park 方法,日志中显示为 java.lang.Thread.State: WAITING (parking)
TIMED_WAITING 正在等待另一个线程执行最多指定等待时间的操作的线程处于此状态。线程因为调用下面的方法之一而处于定时等待状态:
- Thread.sleep 方法
- 指定超时值的 Object.wait 方法
- 指定超时值的 Thread.join 方法
- LockSupport.parkNanos
- LockSupport.parkUntil
TERMINATED 已退出的线程处于此状态。
线程在给定时间点只能处于一种状态。 这些状态是虚拟机状态,不反映任何操作系统线程状态。
7.break和continue的作用
break和continue都是用来控制循环结构的,主要是停止循环。
- break用于完全结束一个循环,跳出循环体执行循环后面的语句。
- continue和break有点类似,区别在于continue只是终止本次循环,接着还执行后面的循环,break则完全终止循环。可以理解为continue是跳过当次循环中剩下的语句,执行下一次循环。
9. 异常处理中throws和throw的区别?
声明异常——throws
java中通过关键词throws声明某个方法可能抛出的各种异常类,可以同时声明多个异常类,但需用逗号隔开。
public void divide() throws Exception1,Exception2{}
有两种方式进行处理throws:
- 1.使用try-catch捕获异常
- 2.使用throws继续声明,如果调用者不打算处理此异常,可以继续通过throws声明异常,让上一级调用者处理异常。main()方法声明的异常将由Java虚拟机来处理
抛出异常——throw
java中也可以使用throw关键词,来进行自行抛出异常,来处理系统无法自动发现并解决的问题,将它由调用者来进行决解
public void setAge(int age) throws Exception { if (age >= 0 && age <= 100) { this.age = age; }else{ throw new Exception("年龄必须在1到100之间"); } }
区别
- 1.作用不同:
- throw用于在程序中抛出异常
- throws用于声明在该方法内抛出了异常
- 2.使用位置不同:
- throw位于方法体内部,用于单独语句使用
- throws需要跟在方法参数列表后面,不能单独使用
- 3.内容不同:
- throw抛出一个异常对象,且只能有一个
- throws后面跟异常类,且可以跟多个异常类
10. 写出冒泡排序和快速排序?
冒泡排序:
//冒泡排序 public class BubbleSortMain { public static void main(String[] args) { int[] arr = {2,5,1,3,8,5,7,4,3}; bubbleSort(arr); ArrayUtil.print(arr); } /** * 冒泡排序 * @param arr */ private static void bubbleSort(int[] arr) { if(arr==null || arr.length < 2 ){ return; } for (int i = 0; i < arr.length - 1; i++) { for (int j = 0; j < arr.length - i -1; j++) { // 这里说明为什么需要-1 if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } }
快速排序
//随机快速排序 /** * 快速排序,使得整数数组 arr 有序 */ public static void quickSort(int[] arr) { if (arr == null || arr.length < 2) { return; } quickSort(arr, 0, arr.length - 1); } /** * 快速排序,使得整数数组 arr 的 [L, R] 部分有序 */ public static void quickSort(int[] arr, int L, int R) { if(L < R) { // 把数组中随机的一个元素与最后一个元素交换,这样以最后一个元素作为基准值实际上就是以数组中随机的一个元素作为基准值 swap(arr, new Random().nextInt(R - L + 1) + L, R); int[] p = partition(arr, L, R); quickSort(arr, L, p[0] - 1); quickSort(arr, p[1] + 1, R); } } /** * 分区的过程,整数数组 arr 的[L, R]部分上,使得: * 大于 arr[R] 的元素位于[L, R]部分的右边,但这部分数据不一定有序 * 小于 arr[R] 的元素位于[L, R]部分的左边,但这部分数据不一定有序 * 等于 arr[R] 的元素位于[L, R]部分的中间 * 返回等于部分的第一个元素的下标和最后一个下标组成的整数数组 */ public static int[] partition(int[] arr, int L, int R) { int basic = arr[R]; int less = L - 1; int more = R + 1; while(L < more) { if(arr[L] < basic) { swap(arr, ++less, L++); } else if (arr[L] > basic) { swap(arr, --more, L); } else { L++; } } return new int[] { less + 1, more - 1 }; } /* * 交换数组 arr 中下标为 i 和下标为 j 位置的元素 */ public static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; }
国庆大礼包 简答题(每道题20分,共100分)
1.Redis的持久化方式有哪些?各有何利弊?
参考网址:https://blog.csdn/meism5/article/details/104245215
Redis 提供两种持久化机制: RDB 和 AOF
RDB Redis DataBase:
指用数据集快照的方式半持久化模式,记录 redis 数据库的所有键值对,在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,可恢复数据
优点:
- 只有一个文件 dump.rdb,恢复操作简单,容灾性好
- 性能较高,fork 子进程进行写操作,主进程继续处理命令
- 大数据集比 AOF 的恢复效率高
缺点:
- 数据安全性低,RDB 是每间隔一段时间进行持久化,若期间 redis 发生故障,可能会发生数据丢失
AOF Append-only file
指所有的命令行记录以 redis 命令请求协议的格式完全持久化存储,保存为 aof 文件
优点:
- 数据安全,aof 持久化可以配置 appendfsync 属性为 always,记录每个命令操作到 aof 文件中一次;通过 append 模式写文件,即使中途服务器宕机,也可以通过 redis-check-aof 工具解决数据一致性问题
- AOF 机制的 rewrite 模式,AOF 文件没被 rewrite 之前可以进行处理,如删除文件中的 flushall 命令
缺点:
- AOF 的持久化文件比 RDB 大,恢复速度慢
2.说一下 mybatis 的一级缓存和二级缓存?
参考网址:https://blog.csdn/huangli1466384630/article/details/82432128
一级缓存
Mybatis的一级缓存是指Session缓存。一级缓存的作用域默认是一个SqlSession。Mybatis默认开启一级缓存。
也就是在同一个SqlSession中,执行相同的查询SQL,第一次会去数据库进行查询,并写到缓存中;第二次以后是直接去缓存中取。
当执行SQL查询中间发生了增删改的操作,MyBatis会把SqlSession的缓存清空。一级缓存的范围有SESSION和STATEMENT两种,默认是SESSION,如果不想使用一级缓存,可以把一级缓存的范围指定为STATEMENT,这样每次执行完一个Mapper中的语句后都会将一级缓存清除。
如果需要更改一级缓存的范围,可以在Mybatis的配置文件中,在下通过localCacheScope指定。
1
<setting name=
"localCacheScope"
value=
"STATEMENT"
/>
建议不需要修改
需要注意的是
当Mybatis整合Spring后,直接通过Spring注入Mapper的形式,如果不是在同一个事务中每个Mapper的每次查询操作都对应一个全新的SqlSession实例,这个时候就不会有一级缓存的命中,但是在同一个事务中时共用的是同一个SqlSession。
如有需要可以启用二级缓存。
二级缓存
Mybatis的二级缓存是指mapper映射文件。二级缓存的作用域是同一个namespace下的mapper映射文件内容,多个SqlSession共享。Mybatis需要手动设置启动二级缓存。
二级缓存是默认启用的(要生效需要对每个Mapper进行配置),如想取消,则可以通过Mybatis配置文件中的元素下的子元素来指定cacheEnabled为false。
1
2
3
<settings>
<setting name=
"cacheEnabled"
value=
"false"
/>
</settings>
cacheEnabled默认是启用的,只有在该值为true的时候,底层使用的Executor才是支持二级缓存的CachingExecutor。
要使用二级缓存除了上面一个配置外,我们还需要在我们每个DAO对应的Mapper.xml文件中定义需要使用的cache
1
2
3
4
5
...
<mapper namespace=
"...UserMapper"
>
<cache/><!-- 加上该句即可,使用默认配置、还有另外一种方式,在后面写出 -->
...
</mapper>
二级缓存的使用原则
- 只能在一个命名空间下使用二级缓存
由于二级缓存中的数据是基于namespace的,即不同namespace中的数据互不干扰。在多个namespace中若均存在对同一个表的操作,那么这多个namespace中的数据可能就会出现不一致现象。- 在单表上使用二级缓存
如果一个表与其它表有关联关系,那么久非常有可能存在多个namespace对同一数据的操作。而不同namespace中的数据互补干扰,所以就有可能出现多个namespace中的数据不一致现象。- 查询多于修改时使用二级缓存
在查询操作远远多于增删改操作的情况下可以使用二级缓存。因为任何增删改操作都将刷新二级缓存,对二级缓存的频繁刷新将降低系统性能。
3.说一下 ACID 是什么?
ACID,是指在可靠数据库管理系统(DBMS)中,事务(transaction)所应该具有的四个特性:
原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability).
这是可靠数据库所应具备的几个特性.所以ACID就是这四大特性的缩写。
- 原子性(Atomicity)
原子性意味着数据库中的事务执行是作为原子。即不可再分,整个语句要么执行,要么不执行。
在SQL SERVER中,每一个单独的语句都可以看作是默认包含在一个事务之中,每一个语句本身具有原子性,要么全部执行,这么全部不执行,不会有中间状态:
例如:
银行转账功能,从A账户减去100,在B账户增加100,如果这两个语句不能保证原子性的话,比如从A账户减去100后,服务器断电,而在B账户中却没有增加100.虽然这种情况会让银行很开心,但作为开发人员的你可不希望这种结果.而默认事务中,即使出错了也不会整个事务进行回滚。而是失败的语句抛出异常,而正确的语句成功执行。这样会破坏原子性。所以SQL SERVER给予了一些选项来保证事务的原子性。- 一致性(Consistency)
一致性即在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
一致性体现在两个层面:
1.数据库机制层面
数据库层面的一致性是,在一个事务执行之前和之后,数据会符合你设置的约束(唯一约束,外键约束,Check约束等)和触发器设置.这一点是由SQL SERVER进行保证的.
2.业务层面
对于业务层面来说,一致性是保持业务的一致性.这个业务一致性需要由开发人员进行保证.很多业务方面的一致性可以通过转移到数据库机制层面进行保证.比如,产品只有两个型号,则可以转移到使用CHECK约束使某一列必须只能存这两个型号.- 隔离性(Isolation)
隔离性。事务的执行是互不干扰的,一个事务不可能看到其他事务运行时,中间某一时刻的数据。
在Windows中,如果多个进程对同一个文件进行修改是不允许的,Windows通过这种方式来保证不同进程的隔离性,而SQL Server中,通过SQL SERVER对数据库文件进行管理,从而可以让多个进程可以同时访问数据库:SQL Server利用加锁和阻塞来保证事务之间不同等级的隔离性.
一般情况下,完全的隔离性是不现实的,完全的隔离性要求数据库同一时间只执行一条事务,这样的性能可想而知.想要理解SQL Server中对于隔离性的保障,首先要了解事务之间是如何干扰的.事务之间的互相影响的情况分为几种,分别为:脏读(Dirty Read),不可重复读,幻读。- 持久性(Durability)
持久性,意味着在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。即使出现了任何事故比如断电等,事务一旦提交,则持久化保存在数据库中.
4.说一下 spring 的事务隔离?
参考网址:https://blog.csdn/qq_37651267/article/details/92425172
http://www.mianshigee/question/10481uai
事务产生的问题
场景:同一个事务内(同一个服务内)
名称 数据的状态 实际行为 产生原因 脏读 未提交 打算提交但是数据回滚了,读取了提交的数据 数据的读取 不可重复读 已提交 读取了修改前的数据 数据的修改 幻读 已提交 读取了插入前的数据 数据的插入 数据库事务隔离级别
名称 结果 脏读 不可重复读 幻读 Read UnCommitted(读未提交) 什么都不解决 √ √ √ Read Committed(读提交) 解决了脏读的问题 – √ √ Repeatable Read(重复读) (mysql的默认级别)解决了不可重复读 ) – – √ Serializable(序列化) 解决所有问题 – – –
- READ UNCOMMITTED(读未提交数据):允许事务读取未被其他事务提交的变更数据,会出现脏读、不可重复读和幻读问题。
- READ COMMITTED(读已提交数据):只允许事务读取已经被其他事务提交的变更数据,可避免脏读,仍会出现不可重复读和幻读问题。
- REPEATABLE READ(可重复读):确保事务可以多次从一个字段中读取相同的值,在此事务持续期间,禁止其他事务对此字段的更新,可以避免脏读和不可重复读,仍会出现幻读问题。
- SERIALIZABLE(序列化):确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作,可避免所有并发问题,但性能非常低。
Spring隔离级别
int ISOLATION_DEFAULT = -1; 默认采用数据库的隔离级 int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED; //0000 0001 -> 1 int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED; //0000 0010-> 2 int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ; //0000 0100-> 4 int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
spring 有五大隔离级别,默认值为 ISOLATION_DEFAULT(使用数据库的设置),其他四个隔离级别和数据库的隔离级别一致:
ISOLATION_DEFAULT:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;
ISOLATIONREADUNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);
ISOLATIONREADCOMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别;
ISOLATIONREPEATABLEREAD:可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别; ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。
脏读 :表示一个事务能够读取另一个事务中还未提交的数据。比如,某个事务尝试插入记录 A,此时该事务还未提交,然后另一个事务尝试读取到了记录 A。
不可重复读 :是指在一个事务内,多次读同一数据。
幻读 :指同一个事务内多次查询返回的结果集不一样。比如同一个事务 A 第一次查询时候有 n 条记录,但是第二次同等条件下查询却有 n+1 条记录,这就好像产生了幻觉。发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据,同一个记录的数据内容被修改了,所有数据行的记录就变多或者变少了。
5.讲讲 Spring 事务的传播属性。
参考网址:https://www.jianshu/p/e1848e2aa7c3
spring事务传播属性定义在org.springframework.transaction.TransactionDefinition接口,类似于EJB CMT的事务传播属性定义,主要有以下几种类型:
propagation 说明 PROPAGATION_REQUIRED 支持当前事务,如果当前没有事务,则新建一个事务执行 PROPAGATION_SUPPORTS 支持当前事务,如果没有当前事务,则以非事务的方式执行 PROPAGATION_MANDATORY 支持当前事务,如果当前没有事务,则抛出异常 PROPAGATION_REQUIRES_NEW 创建一个新的事务,如果当前已经有事务了,则将当前事务挂起 PROPAGATION_NOT_SUPPORTED 不支持当前事务,而且总是以非事务方式执行 PROPAGATION_NEVER 不支持当前事务,如果存在事务,则抛出异常 PROPAGATION_NESTED 如果当前事务存在,则在嵌套事务中执行,否则行为类似于PROPAGATION_REQUIRED。 EJB中没有类似的功能。
更多推荐
java每日一练:面试题集合
发布评论