目录
1、面向对象的特征有哪些方面?
2、作用域public,private,protected,default以及不写时的区别?
3、String是最基本的数据类型吗?
4、float型float f=3.4是否正确?
5、short s1 = 1; s1 = s1 + 1;有什么错?
6、Java有没有goto?
7、int 和Integer有什么区别?
8、&和&&的区别?
9、简述逻辑操作(&,|,^)与条件操作(&&,||)的区别?
10、stack是什么?
11、MySQL中varchar与char的区别以及varchar(50)中的50代表的涵义?
12、如何解决MySQL中存储中文乱码问题?
13、Float和Double的区别是什么?
14、swtich是否能作用在byte上,是否能作用在long 上,是否能作用在String上?
15、构造器Constructor是否可被override?
16、是否可以继承String类?
17、当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
18、String, StringBuffer StringBuilder的区别。
19、Overload 和Override的区别。Overloaded 的方法是否可以改变返回值的类型?
20、描述一下JVM加载class 文件的原理机制?
21、abstract class 和interface有什么区别?
22、java中会存在内存泄漏吗,请简单描述。
23、静态变量和实例变量的区别?
24、final,finally,finalied有什么区别?
25、静态方法能不能重写?
26、对构造方法的理解?
27、堆和栈的区别
28、float和double的区别
29、HashMap底层原理是什么?
30、Java7 Java8中的 HashMap区别?
31、HashMap扩容机制是什么?
32、ArrayList和LinedList的区别?
33、手写一下HashMap的几种遍历方式
34、Collection和Collections的区别?
35、HasMap 和 Hashtable的区别?
36、Map、List和Set的区别是什么?
37、HashMap,LinkedHashMap,TreeMap区别?底层数据结构?
38、Hash碰撞是什么?怎么解决?
39、创建线程的几种方式是什么?
40、sleep()和wait()有什么区别
41、进程和线程的区别
42、什么是死锁,产生死锁的四个条件
43、线程池有几种?
44、线程池参数有哪些?
45、什么是节点流,什么是过滤流,并且说出常用的节点流和过滤流?
46、什么叫对象序列化,什么是反序列化,实现对象序列化需要做哪些工作?
47、http和https的区别
48、三次握手四次挥手
49、TCP/UDP的区别
50、常见的通讯协议
51、HTTP请求结构?HTTP请求头中有什么?
52、GET和POST的区别
53、 java 容器都有哪些?
54、Collection 和 Collections 有什么区别?
55、List、Set、Map 之间的区别是什么?
56、如何决定使用 HashMap 还是 TreeMap?
57、如何实现数组和 List 之间的转换?
58、Array 和 ArrayList 有何区别?
59、迭代器 Iterator 是什么?
60、Iterator 怎么使用?有什么特点?
61、Iterator 和 ListIterator 有什么区别?
62、怎么确保一个集合不能被修改?
63、throw 和 throws 的区别?
64、try-catch-finally 中哪个部分可以省略?
65、try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
66、常见的异常类有哪些?
67、http 响应码 301 和 302 代表的是什么?有什么区别?
68、并行和并发有什么区别?
69、线程和进程的区别?
70、守护线程是什么?
71、notify()和 notifyAll()有什么区别?
72、线程的 run()和 start()有什么区别?
73、线程池都有哪些状态?
74、线程池中 submit()和 execute()方法有什么区别?
75、在 java 程序中怎么保证多线程的运行安全?
76、说一下 synchronized 底层实现原理?
77、synchronized 和 Lock 有什么区别?
78、synchronized 和 volatile 的区别是什么?
79、为什么要使用 spring?
80、spring 常用的注入方式有哪些?
81、spring 中的 bean 是线程安全的吗?
82、spring 支持几种 bean 的作用域?
83、spring 自动装配 bean 有哪些方式?
84、spring 事务实现方式有哪些?
85、说一下 spring 的事务隔离?
86、spring mvc 有哪些组件?
87、@RequestMapping 的作用是什么?
88、动态代理是什么?有哪些应用?
89、怎么实现动态代理?
90、深拷贝和浅拷贝区别是什么?
91、数据库的三范式是什么?
92、一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 mysql 数据库,又插入了一条数据,此时 id 是几?
93、如何获取当前数据库版本?
94、说一下 ACID 是什么?
95、mysql 的内连接、左连接、右连接有什么区别?
96、mysql 索引是怎么实现的?
97、怎么验证 mysql 的索引是否满足需求?
98、说一下数据库的事务隔离?
99、说一下 mysql 常用的引擎?
100、说一下 mysql 的行锁和表锁?
101、mysql 问题排查都有哪些手段?
102mybatis 中 #{}和 ${}的区别是什么?
103、mybatis 有几种分页方式?
104、mybatis 逻辑分页和物理分页的区别是什么?
105、mybatis 是否支持延迟加载?延迟加载的原理是什么?
106、说一下 mybatis 的一级缓存和二级缓存?
107、mybatis 有哪些执行器(Executor)?
108、mybatis 分页插件的实现原理是什么?
109、Spring如何解决循环依赖问题?
110、Spring两大核心技术是什么?
111、简单描述下你对AOP和IOC的理解?
112、AOP是如何实现的?
113、简述Spring中常用的几种Advice注解
114、CGLIB代理和JDK代理的区别?
115、@Autowired和@Resource注解的区别?
116、事务注解以及作用?
117、Spring 事务
118、Spring(Spring Boot) 常用注解有哪些?都有什么用?
119、java配置类相关注解@Configuration 声明当前类为配置类
120、切面(AOP)相关注解
121、测试相关注解
122、依赖注入的三种方式?
123、Spring MVC、Spring Cloud、Spring Boot的区别是什么?
124、Spring 和 Spring Boot 的区别?
125、Spring Boot自动配置原理
126、Spring MVC的设计理念
127、Spring MVC的处理流程?
128、Spring MVC 常用注解
129、如何处理get请求?
130、MyBatis #{}和${}的区别
131、MyBatis怎么防止SQL注入
132、MyBatis的一级缓存二级缓存?
133、MyBatis如何不走一级缓存?
134、简述MyBatis的单个参数、多个参数如何声明?
135、MyBatis缓存优先级?
136、MyBatis和MyBatis plus的区别
137、MyBatis如何实现分页?
138、写过原生的分页吗?用过什么插件吗?分页插件的原理?
139、JDBC跟Mybatis区别
答:面向对象的特征主要有以下几个方面:
1)继承:继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并且类可以修改或增加新的方法使之更适合特殊的需要。
2)封装:封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。
3)多态性:多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。
答:区别如下:
作用域 当前类 同包 子孙类 其他
public √ √ √ √
protected √ √ √ ×
default √ √ × ×
private √ × × ×
不写时默认为default,但注意此单词不能写出,写出会报错.
答:不是.String是引用类型,底层维护的是char类型的数组
答:不正确.浮点型的字面值类型是double,所以应该强制类型转换3.4为float类型float f=(float)3.4
short s1 = 1; s1 += 1;有什么错?
答:short s1 = 1; s1 = s1 + 1;s1+1运算结果是int 型,
需要强制转换类型;short s1 = 1; s1 += 1;可以正确编译,自动类型提升。
答:goto 是java 中的保留字,现在没有在java 中使用。
答:Java 提供两种不同的类型:引用类型和原始类型(或基本类型);
int 是java 的原始数据类型,Integer 是java 为int 提供的封装类。
Java 为每个原始类型提供了封装类:
原始类型: boolean,char,byte,short,int,long,float,double
封装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double引用类型和基本类型的行为完全不同,并且它们具有不同的语义。引用类型和基本类型具有不同的特征和用法,它们包括:大小和速度问题,这种类型以哪种类型的数据结构存储,当引用类型和基本类型用作某个类的实例数据时所指定的默认值。对象引用实例变量的默认值为null,而基本类型实例变量的默认值与它们的类型有关。
答:&是位运算符,表示按位与运算,&&是逻辑运算符,表示逻辑与(and),有短路的作用。
答:区别主要有两点:
1. 条件操作只能操作布尔型的,而逻辑操作不仅可以操作布尔型,而且可以操作数值型
2. 逻辑操作不会产生短路。
答:栈是一种线形集合,其添加和删除元素的操作按照后进先出的方式进行处理;
答案:
Varchar是变长字符串,最多存储的大小是65535字节,查询速度相对较慢;
Char 是定常字符串,最多存储的大小是255字节,查询速度相对较快
- varchar(50)表示:Mysql 4.0 表示存放50个字节,5.0存放50个字符。
答案:
- 脚本文件采用UTF8编码
- 客户端连接数据库使用UTF8编码
- 服务器端创建数据库使用UTF8编码
答案:
FLOAT(单精度浮点数)类型 数据可以存储至多8位十进制数,并在内存中占4字节。
DOUBLE(双精度浮点数)类型 数据可以存储至多18位十进制数,并在内存中占8字节
答:switch(express)中,express 是一个整数表达式,支持的参数参数有:byte、int、short、char、String与enum
答:构造器Constructor 不能被继承,因此不能重写Overriding,但可以被重载Overloading。
答:String 类是final 类,故不可以继承。
答:是值传递。Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的。
答:String 的长度是不可变的;StringBuffer 的长度是可变的,如果你对字符串中的内容经常进行操作,特别是内容要修改时,那么使用StringBuffer,如果最后需要String,那么使用StringBuffer 的toString()方法;线程安全;StringBuilder 是从JDK 5 开始,为StringBuffer 该类补充了一个单个线程使用的等价类;通常应该优先使用StringBuilder 类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。
答:方法的重写Overriding 和重载Overloading 是Java 多态性的不同表现。
重写Overriding 是父类与子类之间多态性的一种表现,
重载Overloading 是一个类中多态性的一种表现。
如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写(Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。
如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded 的方法是可以改变返回值的类型。
答:JVM 中类的装载是由ClassLoader 和它的子类来实现的,Java ClassLoader是一个重要的Java 运行时系统组件。它负责在运行时查找和装入类文件的类。
答:
1抽象类是一个特殊的类,特殊在,抽象类中可以包含没有方法体的方法(抽象方法)
2接口可以理解成一个特殊的抽象类,特殊在,接口里的都是抽象方法,没有普通方法
3接口会为方法自动拼接public abstract,还会为变量自动拼接public final static
4抽象类可以有构造方法–用来给子类创建对象,接口中没有构造方法
5抽象类和接口都不能实例化(创建对象)
6接口可继承接口,并可多继承接口,但类只能单继承
7抽象方法只能声明,不能实现,接口是设计的结果 ,抽象类是重构的结果
答:会;存在无用但可达的对象,这些对象不能被GC 回收,导致耗费内存资源。
答:静态变量也称为类变量,归全类共有,它不依赖于某个对象,可通过类名直接访问;而实例变量必须依存于某一实例,只能通过对象才能访问到它。
final修饰符(关键字)
被final修饰的类,就意味着不能再派生出新的子类。
被final声明的变量初始化后,只能读取不能修改。
被final声明的方法不能在子类中重写。
finally
是在异常处理时的finally块。不管有没有异常被抛出、捕获,finally块都会被执行。
finalize
finalize是方法名。它是在Object类中定义的,因此所有的类都继承了它。
finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。
静态方法不能被重写,重写是建立在动态执行基础上的,Java静态方法是静态绑定执行的,不能重写
1.构造器即构造函数或构造方法(constructor),其本质是一个特殊的方法,用来初始化对象。
2.构造器的名称要与类的名称一致。
3.如果没有定义构造器,则会自动添加一个无参构造函数;
4.构造方法也可以重载。
什么是堆内存?
堆内存是Java内存区域,它的作用是用于存储Java中的对象,当我们new一个对象时候就会在堆内存中开辟一段空间存储对象。需要垃圾回收器回收对内存中无用的垃圾对象。多个线程共享同一个堆内存。
什么是栈内存
栈内存是Java的内存区域,每个线程都有一个独立的栈内存,主要是用来存储方法执行的局部变量,方法参数和this变量就在栈内存。随着调用方法开辟栈帧,方法调用结束就销毁对应的栈帧,方法中分配的局部变量也随栈帧销毁。
- float 单精度浮点数在机内占 4 个字节,用 32 位二进制描述。精度不高,因为精度不高所以不常用。
- double 双精度浮点数在机内占 8 个字节,用 64 位二进制描述。精度大于是float的两倍,顾称为双倍精度浮点数。因为精度高,便于保持运算的精确性,是最常用的浮点数类型。
Java浮点数采用IEEE-754标注
1.HashMap底层是一个散列桶数组,每个散列桶是一个单向链表结构
2.散列桶容量从16开始,每次扩容为2倍
3.当出现散列冲突时候,散列桶中元素形成链表结构。当散列表容量大于64,散列桶中元素超过8个时候,会转换为红黑树,来提升查询性能。
4.查找时候,利用散列算法,计算到散列桶位置,直接定位到散列桶定位。定位速度很快
5.散列表加载因子是75%,也就是最多75%充满率,出现散列冲突机会少,严重散列冲突还有红黑树优化,在散列桶中查询性能很快。
- Java 7 采用:散列桶数组+链表方式实现,Java7 以前,Java很少管理超过2GB的内存,散列数组很少会达到数组上限,利用适当数组扩容就可以减少因为散列冲突出现的链表长度问题,就可以解决链表查询性能问题。
- Java 8 采用:散列桶数组+链表/红黑树方式实现。Java 8 时代是大数据时代,Java面对的内存经常2GB内存,理论上,散列桶数组完全可能达到Java数组的上限2G,不能通过扩容解决散列冲突问题,Java8的优化方法就是引入了红黑树!
利用红黑树解决链表查询问题。
在链表长度超过8个节点时候转换为红黑树。
实例化的 HashMap 默认内部数组是 null。第一次调 用 put 方法时初始化,长度为 16。
创建HashMap时候设定了扩容阈值,默认的散列数组容量的75%。
添加元素时候先添加元素,然后判断是否需要扩容,如果容量达到阈值, 则容量变为原来的 2 倍,阈值也变为原来的 2 倍,作为下次扩容的阈值。
扩容后数组长度始终是2的整次幂,这个是散列算法的要求。
数据结构实现:ArrayList :基于数组,容量不够时候采用复制方式扩容。LinkedList:使用链表实现。
随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为LinkedList 是链表结构,需要依次查找元素,性能不高。
增加和删除效率: LinkedList 首位操作具备很高效率。ArrayList 的头部性能稍差。
线程安全:ArrayList 和 LinkList 都是不同步的,不保证线程安全。
综合来说,需要频繁读取集合中的元素时,更推荐使用 Arrayist;
而在头尾增删操作较多时,更推荐使用 LinkedList。ArrayList综合性能优秀,优选之!
Entry 遍历
keySet 遍历
foreach遍历
keySet foreach遍历
1.Collection 是一个集合接口,集合类的一个顶级接口。它定义了集合通用方法。
2.Collection 接口直接继承接口有 List 与 Set。
3.Collections 则是集合类的一个工具类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
1.线程是否安全:
HashMap 是非线程安全的,Hashtable 是线程安全的。(如果你要保证线程安全的话 就使用 ConcurrentHashMap 吧!);
2. 效率:
因为线程安全的问题,HashMap 要比 Hashtable 效率高一点。另外,
Hashtable 基本被淘汰,不要在代码中使用它;
3.对 Null 的支持:
HashMap 可以存储 null 的 key 和 value,但 null 作为Key只能有一个,null 作为值可以有多个;Hashtable 不允许有 null 键和 null 值,否 则会抛出NullPointerException。
1.List 线性表,有序可以重复的集合,元素有先后次序,可以按照位置访问元素,可以存储null
2.Set 元素不重复集合,重复元素算一个,不保证元素的先后次序,可以存储一个null
3.Map元素按照key:value成对存储,可以按照key查找value,查找性能好,key不可以重复,可以存储一个null key
HashMap :内部是一个散列表,查找数据性能很高。
LinkedHashMap 基本特点:继承自 HashMap,对 Entry 集合添加了一个双向链表。
TreeMap 内部的红黑树,也就是二叉树,按照key进行排序。
- 散列计算时候,当两个不同的key.hashCode(),计算出相同的散列值的现象,我们就把它叫做散列冲突(哈希碰撞)。
HashMap中的解决办法是利用链表结构存储,超过8个元素时候转换为红黑树。
元素数量超过阈值时候,扩容也可以减少散列冲突。
- 双向链表/双向循环链表
通过继承 Thread 类创建线程类。
实现 Runnable 接口创建线程类。
通过 Callable 和 Future 接口创建线程
1.sleep方法是Thread类的静态方法;wait方法是Object类的成员方法;
2.sleep方法使当前线程暂停执行指定的时间,让出cpu给其他线程。在调用sleep方法后,线程不会释放对象锁;而当调用wait方法时,线程会放弃对象锁,进入等待队列,只有针对此对象调用notify()方法后本线程才进入对象锁定池处于准备状态。
3.sleep方法可以在任何地方使用;wait方法只能在同步方法和同步代码块中使用
进程是资源分配的最小单位,线程是CPU调度的最小单位。
操作系统执行程序时候,按照进程分配内存等资源,而执行程序时候以线程为单位执行程序中的指令。
一个进程内部包含多个并发执行的线程。
在进程内部多个线程共享一个进程的内存资源。
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
Java通过Executors(JUC)提供四种线程池,分别为:
1.newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活 回收空闲线程,若无可回收,则新建线程。
2.newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队 列中等待。
3.newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
4.newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作 线程来执 行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
corePoolSize 核心线程大小。
maximumPoolSize 线程池最大线程数量。
keepAliveTime 空闲线程存活时间。
unit 空间线程存活时间单位。
workQueue 工作队列。
threadFactory 线程工厂。
handler 拒绝策略。
- 节点流:可以从或向一个特定的地方(节点)读写数据,直接跟数据源相接。
FileInputStream FileOutputStrean
ByteArrayInputStream ByteArrayOutputStream
- 过滤流:是对一个已存在的流的的基础上进行功能扩展。
BufferedImputStrean BufferedOutputStream
InputStreamReader OutputStreamWriter
ObjectInputStream ObjectOutputStream
- 序列化:把对象转化为可传输的字节序列过程称为序列化。
- 反序列化:把字节序列还原为对象的过程称为反序列化。
- 其实序列化最终的目的是为了对象数据存储,或者进行网络传输
- java 实现序列化很简单,只需要被序列化对象类实现Serializable 接口,然后
使用对象流进行序列化和反序列化。
使用ObjectOutputStream 进行对象序列化
使用ObjectInputStream 进行对象反序列化
- HTTP协议是什么?
HTTP协议是超文本传输协议的缩写,英文是Hyper Text Transfer Protocol。它是从WEB服务器传输超文本标记语言(HTML)到本地浏览器的传送协议。
- HTTPS协议是什么
HTTPS(全称:Hypertext Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即 HTTP+SSL=HTTPS。
https协议需要到CA申请证书,一般免费证书较少,因而需要一定费用。
http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl/tls加密传输协议。
http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
http的连接很简单,是无状态的;HTTPS协议是由SSL/TLS+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
- 三次握手的原文是 three-way handshake,整个名词的可以翻译为:需要三个步骤才能建立握手/连接的机制。当然,三次握手也可以叫 three-messagehandshake,通过三条消息来建立的握手/连接。
- 第一次握手:客户端什么都不能确认;服务器确认了对方发送正常,自己 接收正常
- 第二次握手:客户端确认了:自己发送、接收正常,对方发送、接收正常; 服务器确认了:对方发送正常,自己接收正常
- 第三次握手(客户端发送 ACK 报文给服务器): 客户端确认了:自己发送、接收正常,对方发送、接收正常;服务器确认了:自己发送、接收正常,对方发送、接收正常
- TCP 连接的释放需要发送四个包(执行四个步骤),因此称为四次挥手(Four-way handshake),客户端或服务端均可主动发起挥手动作。通俗的来说,两次挥手就可以释放一端到另一端的 TCP 连接,完全释放连接一共需要四次挥手。
TCP 基于连接,UDP 基于无连接。
TCP 要求系统资源较多,UDP 较少。
UDP 程序结构较简单。
TCP 保证数据正确性,UDP 可能丢包。
TCP 保证数据顺序,UDP 不保证。
TCP/IP是个协议组,可分为四个层次:网络接口层、网络层、传输层和应用层。
在网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。
在传输层中有TCP协议与UDP协议。
在应用层有FTP、HTTP、TELNET、SMTP、DNS等协议
- 一个HTTP请求报文由四个部分组成:请求行、请求头部、空行、请求数据
- 2.请求头
1.Accept:浏览器可接受的mime类型。
2.Accept-Charset:浏览器可接受的字符集。
3.Accept-Encoding:浏览器能够进行解码的方式。
4.Content-Length:表示请求消息的长度。
5.Host: 客户端告诉服务器,想访问的主机名。
6.Cookie:客户端可以向服务器带数据,只是非常重要的信息之一。
GET方式是通过请求行传递用户所输入的内容,其内容会全部显示的浏览器
的地址栏中;
GET提交具有长度限制
GET是从服务器上获取数据
GET请求没有HTTP消息体
- POST提交将用户所输入数据放到HTTP消息体中发送到服务器端
POST没有提交长度限制
POST是向服务器传送数据
java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。
Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。然而,假如你需要对一个有序的key集合进行遍历,TreeMap是更好的选择。基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为TreeMap进行有序key的遍历。
List转换成为数组:调用ArrayList的toArray方法。
数组转换成为List:调用Arrays的asList方法。
Array可以容纳基本类型和对象,而ArrayList只能容纳对象。
Array是指定大小后不可变的,而ArrayList大小是可变的。
Array没有提供ArrayList那么多功能,比如addAll、removeAll和iterator等。
迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
Java中的Iterator功能比较简单,并且只能单向移动:
(1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。
(2) 使用next()获得序列中的下一个元素。
(3) 使用hasNext()检查序列中是否还有元素。
(4) 使用remove()将迭代器新返回的元素删除。
Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。
Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。
Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。
ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。
可以使用 Collections. unmodifiableCollection(Collection c) 方法来创建一个只读集合,这样改变集合的任何操作都会抛出 Java. lang. UnsupportedOperationException 异常。
throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理。而throw则是指抛出的一个具体的异常类型。
答:catch 可以省略
更为严格的说法其实是:try只适合处理运行时异常,try+catch适合处理运行时异常+普通异常。也就是说,如果你只用try去处理普通异常却不加以catch处理,编译是通不过的,因为编译器硬性规定,普通异常如果选择捕获,则必须用catch显示声明以便进一步处理。而运行时异常在编译时没有如此规定,所以catch可以省略,你加上catch编译器也觉得无可厚非。
理论上,编译器看任何代码都不顺眼,都觉得可能有潜在的问题,所以你即使对所有代码加上try,代码在运行期时也只不过是在正常运行的基础上加一层皮。但是你一旦对一段代码加上try,就等于显示地承诺编译器,对这段代码可能抛出的异常进行捕获而非向上抛出处理。如果是普通异常,编译器要求必须用catch捕获以便进一步处理;如果运行时异常,捕获然后丢弃并且+finally扫尾处理,或者加上catch捕获以便进一步处理。
至于加上finally,则是在不管有没捕获异常,都要进行的“扫尾”处理。
答:会执行,在 return 前执行。
NullPointerException:
当应用程序试图访问空对象时,则抛出该异常。
SQLException:
提供关于数据库访问错误或其他错误信息的异常。
IndexOutOfBoundsException:
指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
NumberFormatException:
当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。
FileNotFoundException:
当试图打开指定路径名表示的文件失败时,抛出此异常。
IOException:
当发生某种I/O异常时,抛出此异常。此类是失败或中断的I/O操作生成的异常的通用类。
ClassCastException:
当试图将对象强制转换为不是实例的子类时,抛出该异常。
ArrayStoreException:
试图将错误类型的对象存储到一个对象数组时抛出的异常。
IllegalArgumentException:
抛出的异常表明向方法传递了一个不合法或不正确的参数。
ArithmeticException:
当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。
NegativeArraySizeException:
如果应用程序试图创建大小为负的数组,则抛出该异常。
NoSuchMethodException:
无法找到某一特定方法时,抛出该异常。
SecurityException:
由安全管理器抛出的异常,指示存在安全侵犯。
UnsupportedOperationException:
当不支持请求的操作时,抛出该异常。
RuntimeExceptionRuntimeException:
是那些可能在Java虚拟机正常运行期间抛出的异常的超类。
答:301,302 都是HTTP状态的编码,都代表着某个URL发生了转移。
301 redirect: 301 代表永久性转移(Permanently Moved)。
302 redirect: 302 代表暂时性转移(Temporarily Moved )。
并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。
在一台处理器上“同时”处理多个任务,在多台处理器上同时处理多个任务。如hadoop分布式集群。
所以并发编程的目标是充分的利用处理器的每一个核,以达到最高的处理性能。
简而言之,进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程。进程在执行过程中拥有独立的内存单元,而多个线程共享内存资源,减少切换次数,从而效率更高。线程是进程的一个实体,是cpu调度和分派的基本单位,是比程序更小的能独立运行的基本单位。同一进程中的多个线程之间可以并发执行。
守护线程(即daemon thread),是个服务线程,准确地来说就是服务其他的线程。
如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争。
优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体。通过调用Thread类的start()方法来启动一个线程。
start()方法来启动一个线程,真正实现了多线程运行。这时无需等待run方法体代码执行完毕,可以直接继续执行下面的代码; 这时此线程是处于就绪状态, 并没有运行。 然后通过此Thread类调用方法run()来完成其运行状态, 这里方法run()称为线程体,它包含了要执行的这个线程的内容, Run方法运行结束, 此线程终止。然后CPU再调度其它线程。
run()方法是在本线程里的,只是线程里的一个函数,而不是多线程的。 如果直接调用run(),其实就相当于是调用了一个普通函数而已,直接待用run()方法必须等待run()方法执行完毕才能执行下面的代码,所以执行路径还是只有一条,根本就没有线程的特征,所以在多线程执行时要使用start()方法而不是run()方法。
线程池有5种状态:Running、ShutDown、Stop、Tidying、Terminated。
接收的参数不一样
submit有返回值,而execute没有
submit方便Exception处理
线程安全在三个方面体现:
原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作,(atomic,synchronized);
可见性:一个线程对主内存的修改可以及时地被其他线程看到,(synchronized,volatile);
有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序,(happens-before原则)。
synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性。
Java中每一个对象都可以作为锁,这是synchronized实现同步的基础:
普通同步方法,锁是当前实例对象
静态同步方法,锁是当前类的class对象
同步方法块,锁是括号里面的对象
首先synchronized是java内置关键字,在jvm层面,Lock是个java类;
synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可);
Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。
volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。
volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。
volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。
1.简介
目的:解决企业应用开发的复杂性
功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
范围:任何Java应用
简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
2.轻量
从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。
3.控制反转
Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。
4.面向切面
Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
5.容器
Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。
6.框架
Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。
所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。
91.解释一下什么是 aop?
AOP(Aspect-Oriented Programming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。
使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说,AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”
Spring通过DI(依赖注入)实现IOC(控制反转),常用的注入方式主要有三种:
构造方法注入
setter注入
基于注解的注入
Spring容器中的Bean是否线程安全,容器本身并没有提供Bean的线程安全策略,因此可以说spring容器中的Bean本身不具备线程安全的特性,但是具体还是要结合具体scope的Bean去研究。
当通过spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。Spring支持如下5种作用域:
singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例
prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例
equest:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效
session:对于每次HTTP Session,使用session定义的Bean豆浆产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效
globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效
其中比较常用的是singleton和prototype两种作用域。对于singleton作用域的Bean,每次请求该Bean都将获得相同的实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为;如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回给程序。在这种情况下,Spring容器仅仅使用new 关键字创建Bean实例,一旦创建成功,容器不在跟踪实例,也不会维护Bean实例的状态。
如果不指定Bean的作用域,Spring默认使用singleton作用域。Java在创建Java实例时,需要进行内存申请;销毁实例时,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此,prototype作用域Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成功,可以重复使用。因此,除非必要,否则尽量避免将Bean被设置成prototype作用域。
Spring容器负责创建应用程序中的bean同时通过ID来协调这些对象之间的关系。作为开发人员,我们需要告诉Spring要创建哪些bean并且如何将其装配到一起。
spring中bean装配有两种方式:
隐式的bean发现机制和自动装配
编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
基于 TransactionProxyFactoryBean 的声明式事务管理
基于 @Transactional 的声明式事务管理
基于 Aspectj AOP 配置事务
事务隔离级别指的是一个事务对数据的修改与另一个并行的事务的隔离程度,当多个事务同时访问相同数据时,如果没有采取必要的隔离机制,就可能发生以下问题:
脏读:一个事务读到另一个事务未提交的更新数据。
幻读:例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还存在没有修改的数据行,就好象发生了幻觉一样。
不可重复读:比方说在同一个事务中先后执行两条一模一样的select语句,期间在此次事务中没有执行过任何DDL语句,但先后得到的结果不一致,这就是不可重复读。
Spring MVC的核心组件:
DispatcherServlet:中央控制器,把请求给转发到具体的控制类
Controller:具体处理请求的控制器
HandlerMapping:映射处理器,负责映射中央处理器转发给controller时的映射策略
ModelAndView:服务层返回的数据和视图层的封装类
ViewResolver:视图解析器,解析具体的视图
Interceptors :拦截器,负责拦截我们定义的请求然后做处理工作
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
RequestMapping注解有六个属性,下面我们把她分成三类进行说明。
value, method:
value:
指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明);
method:
指定请求的method类型, GET、POST、PUT、DELETE等;
consumes,produces
consumes:
指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
produces:
指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
params,headers
arams:
指定request中必须包含某些参数值是,才让该方法处理。
headers:
指定request中必须包含某些指定的header值,才能让该方法处理请求。
动态代理:当想要给实现了某个接口的类中的方法,加一些额外的处理。比如说加日志,加事务等。可以给这个类创建一个代理,故名思议就是创建一个新的类,这个类不仅包含原来类方法的功能,而且还在原来的基础上添加了额外处理的新类。这个代理类并不是定义好的,是动态生成的。具有解耦意义,灵活,扩展性强。
动代理的应用:Spring的AOP、加事务、加权限、加日志
首先必须定义一个接口,还要有一个InvocationHandler(将实现接口的类的对象传递给它)处理类。再有一个工具类Proxy(习惯性将其称为代理类,因为调用他的newInstance()可以产生代理对象,其实他只是一个产生代理对象的工具类)。利用到InvocationHandler,拼接代理类源码,将其编译生成代理类的二进制码,利用加载器加载,并将其实例化产生代理对象,最后返回。
浅拷贝只是复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化,这就是浅拷贝(例:assign())
深拷贝是将对象及值复制过来,两个对象修改其中任意的值另一个值不会改变,这就是深拷贝(例:JSON.parse()和JSON.stringify(),但是此方法无法复制函数类型)
第一范式:强调的是列的原子性,即数据库表的每一列都是不可分割的原子数据项。
第二范式:要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性。
第三范式:任何非主属性不依赖于其它非主属性。
表类型如果是 MyISAM ,那 id 就是 8。
表类型如果是 InnoDB,那 id 就是 6。
InnoDB 表只会把自增主键的最大 id 记录在内存中,所以重启之后会导致最大 id 丢失。
使用 select version() 获取当前 MySQL 数据库版本。
Atomicity(原子性):一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。
Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
内连接关键字:inner join;左连接:left join;右连接:right join。
内连接是把匹配的关联数据显示出来;左连接是左边的表全部显示出来,右边的表显示出符合条件的数据;右连接正好相反。
索引是满足某种特定查找算法的数据结构,而这些数据结构会以某种方式指向数据,从而实现高效查找数据。
具体来说 MySQL 中的索引,不同的数据引擎实现有所不同,但目前主流的数据库引擎的索引都是 B+ 树实现的,B+ 树的搜索效率,可以到达二分法的性能,找到数据区域之后就找到了完整的数据结构了,所有索引的性能也是更好的。
使用 explain 查看 SQL 是如何执行查询语句的,从而分析你的索引是否满足需求。
explain 语法:explain select * from table where type=1。
MySQL 的事务隔离是在 MySQL. ini 配置文件里添加的,在文件的最后添加:transaction-isolation = REPEATABLE-READ
可用的配置值:READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE。
READ-UNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读)。
READ-COMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读)。
REPEATABLE-READ:可重复读,默认级别,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读)。
SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。
脏读 :表示一个事务能够读取另一个事务中还未提交的数据。比如,某个事务尝试插入记录 A,此时该事务还未提交,然后另一个事务尝试读取到了记录 A。
不可重复读 :是指在一个事务内,多次读同一数据。
幻读 :指同一个事务内多次查询返回的结果集不一样。比如同一个事务 A 第一次查询时候有 n 条记录,但是第二次同等条件下查询却有 n+1 条记录,这就好像产生了幻觉。发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据,同一个记录的数据内容被修改了,所有数据行的记录就变多或者变少了。
InnoDB 引擎:InnoDB 引擎提供了对数据库 acid 事务的支持,并且还提供了行级锁和外键的约束,它的设计的目标就是处理大数据容量的数据库系统。MySQL 运行的时候,InnoDB 会在内存中建立缓冲池,用于缓冲数据和索引。但是该引擎是不支持全文搜索,同时启动也比较的慢,它是不会保存表的行数的,所以当进行 select count(*) from table 指令的时候,需要进行扫描全表。由于锁的粒度小,写操作是不会锁定全表的,所以在并发度较高的场景下使用会提升效率的。
MyIASM 引擎:MySQL 的默认引擎,但不提供事务的支持,也不支持行级锁和外键。因此当执行插入和更新语句时,即执行写操作的时候需要锁定这个表,所以会导致效率会降低。不过和 InnoDB 不同的是,MyIASM 引擎是保存了表的行数,于是当进行 select count(*) from table 语句时,可以直接的读取已经保存的值而不需要进行扫描全表。所以,如果表的读操作远远多于写操作时,并且不需要事务的支持的,可以将 MyIASM 作为数据库引擎的首选。
MyISAM 只支持表锁,InnoDB 支持表锁和行锁,默认为行锁。
表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低。
行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高。
使用 show processlist 命令查看当前所有连接信息。
使用 explain 命令查询 SQL 语句执行计划。
开启慢查询日志,查看慢查询的 SQL。
#{}是预编译处理,KaTeX parse error: Expected 'EOF', got '#' at position 21: …串替换; Mybatis在处理#̲{}时,会将sql中的#{}替…{}时,就是把${}替换成变量的值;
使用#{}可以有效的防止SQL注入,提高系统安全性。
数组分页
sql分页
拦截器分页
RowBounds分页
物理分页速度上并不一定快于逻辑分页,逻辑分页速度上也并不一定快于物理分页。
物理分页总是优于逻辑分页:没有必要将属于数据库端的压力加诸到应用端来,就算速度上存在优势,然而其它性能上的优点足以弥补这个缺点。
Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。
它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。
当然了,不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都是一样的。
一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认打开一级缓存。
二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置 ;
对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。
Mybatis有三种基本的执行器(Executor):
SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。
BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。
①构造器的循环依赖:这种依赖spring是处理不了的,直接抛出BeanCurrentlylnCreationException异常。
②单例模式下的setter循环依赖:通过“三级缓存”处理循环依赖,能处理。
③非单例循环依赖:无法处理。原型(Prototype)的场景是不支持循环依赖的,通常会走到AbstractBeanFactory类中下面的判断,抛出异常。
IOC和AOP
IoC/DI
所谓控制反转IoC,只要一个对象的管理控制权交给容器。
依赖注入DI,将一个程序依赖的资源注入到合适的地方
AOP
所谓面向切面编程AOP,是面向对象编程的一种补充,统一管理程序的横向关注点,统一处理横向关注点。常见的场景:安全、日志、审计、事务等
Spring 的 AOP 实现原理其实很简单,就是通过动态代理实现的。
@Before(execution) 在方法执行前拦
@AfterReturning(execution)在方法正常return结束后拦截
@AfterThrowing(execution) 在方法抛出异常时拦截
@After(execution) 在方法结束后拦截,无论正常结束还是异常结束
@Around(execution)唯一可以使ProceedingJoinPoint参数来控制流程的
advice,
在方法执行前拦截,可以在切面逻辑中手动释放拦截,且可以在其后加入逻辑代码,该代码段会在方法执行后执行
JDK代理只能对实现接口的类生成代理,JDK代理使用的是反射机制实现AOP的动态代理;
CGLib是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式。 CGLib代理使用字节码处理框架ASM,通过修改字节码生成子类。
@Autowired 属于Spring框架,默认使用类型(byType)进行注入, 按照类型匹配失败,再按照名字ByName匹配;
@Resource是Java的注解.Spring支持@Resource。而@Resource首选按byName自动注入,如果匹配失败再按照类型byType匹配注入。
简单理解,@Resource的作用相当于@Autowired。 @Autowired首选按byType自动注入,而@Resource首选按byName自动注入。
为单个方法或类上添加事务管理。
标注事务注解的类,其全部方法都有事务
标注了事务注解的方法,默认情况会开启事务,方法中全部功能执行完成以后,自动提交事务,默认情况下,如果方法出现了RuntimeException(含子类型)则会回退事务。
Spring框架的声明式事务管理是通过Spring面向方面编程(AOP)实现的,底层依赖数据库的事务功能。
Spring框架为事务管理提供了一个一致的抽象,在不同的事务API(JDBC、JPA、MyBatis)中具有一致的编程模型。
支持声明式事务管理。与编程式事务相比,编程式事务管理的API更简单。往往只需要在类或者方法上标注 事务注解即可。
Spring框架的声明式事务管理是通过Spring面向方面编程(AOP)实现的,底层依赖数据库的事务功能。
声明bean的注解
@Component 组件,没有明确的角色
@Service 在业务逻辑层使用(service)
@Repository 在数据访问层使用(dao层)
@Controller 在展现层使用,控制器的声明(C)
注册bean的注解
@Autowired :由Spring提供
@Resource :由JSR-250提供
@Bean 注解在方法上,声明当前方法的返回值为一个bean
@ComponentScan 用于对Component进行扫描
@EnableAspectJAutoProxy注解开启Spring对AspectJ代理的支持
@Scope 设置Bean的作用域
@PostConstruct 由JSR-250提供,在构造函数执行完之后执行
@PreDestory 由JSR-250提供,在Bean销毁之前执行
@Value 为属性注入值
@PropertySource 加载配置文件
@EnableScheduling 在配置类上使用,开启计划任务的支持
@Aspect 声明一个切面。AspectJ的注解
@Before 在方法执行之前执行(方法上)
@After 无论是否有异常之后都会执行(方法上)
@AfterThrowing 在方法执行出现异常之后执行(方法上)
@AfterReturing 在方法正常执行之后执行(方法上)
@PointCut 声明切点
@SpringBootTest
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。是Spring全家桶的基石。
Spring MVC是Spring的一个模块,一个web框架。使得开发web应用变得很容易。
Spring配置复杂,繁琐,所以推出了Spring boot,约定优于配置,简化了spring的配置流程。做到开箱即用。
Spring Cloud构建于Spring Boot之上,是一个微服务全家桶方案,可以快速搭建微服务应用。
Spring 框架提供了企业软件的各种基础组件,有了这些基础组件的帮助,开发者就可以更多的聚焦在软件的业务功能,大大提升开发效率。
Spring 的核心功能包括:IoC/DI(依赖注入、控制反转) 和 AOP(面向切面编程)
Spring 还提供了:事务管理、MVC、测试、数据访问等组件
Spring Boot 是以Spring为基础,帮助快速搭建Spring应用程序。开箱即用,几乎不用配置。
Spring Boot 提供了统一的依赖管理,可以很少代码就能整合各种资源,包括JDBC、MyBatis等。
Spring Boot 提供了内嵌服务器、安全、健康检查等开箱即用的功能。
Spring Boot 还提供了打包工具,可以将应用打成Fat Jar,然后一个命令就能启动。
@EnableAutoConfiguration会读取工厂配置 /META-INF/spring.factories
找到 标注@Configuration 的自动配置类
自动配置类中使用 @ConditionalXXX 注解,进行条件配置,根据条件初始化Bean组件
可以根据属性文件、Bean对象,Bean类型自动配置
MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式;Model(模型)表示应用程序核心, 处理应用程序数据逻辑的部分。
View(视图)显示数据。
Controller(控制器)处理输入与交互流程。
1.用户发送请求至前端控制器DispatcherServlet
2.DispatcherServlet收到请求调用处理器映射器HandlerMapping。
3.处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
4.DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
5.执行处理器Handler(Controller,也叫页面控制器)。
6.Handler执行完成返回ModelAndView
7.HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
8.DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9.ViewReslover解析后返回具体View
10.DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
11.DispatcherServlet响应用户。
@Controller:
用于配合组件扫描(@ComponentScan)创建控制器对象,常与@RequestMapping注解结合使用,其元注解包括@Component
@RestController : 一个方便的注解,它元注解有@Controller和@ResponseBody注解。
@ResponseBody: 表明控制器方法的返回值绑定到HTTP响应体
@RequstMapping:使用@RequestMapping注解来映射请求到控制器方法
@PostMapping 用于将HTTP POST请求映射到特定的处理方法的注解
@GetMapping :用于将HTTP GET请求映射到特定的处理方法的注解。
@RequestBody
标注在方法参数上,表示网络请求正文映射到丰富参数。@RequestParam:将请求参数映射到控制器的方法参数上
@PathVariable:将请求路径上“URI模版”映射到控制器的方法参数上
@ResponseStatus: 设定HTTP响应状态码
@RequestHeader:映射请求头到控制器方法参数
@GetMapping :用于将HTTP GET请求映射到特定的处理方法的注解。
@RequstMapping:使用@RequestMapping注解来映射请求到控制器方法,添加请求方式属性
#{}是预编译处理,${}是字符串替换。
MyBatis在处理#{}时,会将sql中的#{}替换为? 号,调用PreparedStatement的set方法来赋值。
MyBatis在处理${}时,就是把${}替换成变量的值, 也就是字符串拼接,字符串拼接存在SQL注入风险。
#{}方式是SQL编译预处理,能够很大程度防止SQL注入,${}方式是直接SQL拼接无法防止SQL注入。
MyBatis一级缓存的生命周期和SqlSession一致。当用户发起查询时,MyBatis先在Local Cache进行查询,如果缓存命中的话,直接返回结果给用户,如果缓存没有命中的话,查询数据库,结果写入Local Cache,最后返回结果给用户。
如果多个SqlSession之间需要共享缓存,则需要使用到二级缓存。级缓存开启后,同一个namespace下的所有操作语句,都影响着同一个Cache,即二级缓存被多个SqlSession共享。数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。
禁用一级缓存:mybatis没有提供一级缓存的启用、禁用开关,但在Mapper文件对应的语句中增加flushCache="true"可以达到实际禁用一级缓存的效果,一般同时还会加上useCache="false"
单个参数直接定义即可
使用@Param注解传递多个参数通过Java Bean传递多个参数
缓存的优先级通过 mybatis 发起的查询,作用顺序为: 二级缓存->一级缓存->数据库
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
Mybatis-Plus是一个Mybatis的增强工具,它在Mybatis的基础上做了增强,却不做改变。我们在使用Mybatis-Plus之后既可以使用Mybatis-Plus的特有功能,又能够正常使用Mybatis的原生功能。
通过 limit 实现分页
RowBounds 实现分页
通过 mybatis 分页插件 PageHelper 实现分页
原生分页就是利用MySQL的 limit 实现分页
通过 mybatis 分页插件 PageHelper 实现分页
PageHeapler 通过MyBatis拦截器实现的分页,核心类是PageInterceptor
你知道MyBatis延迟加载吗?
mybatis的延迟加载就是按需查询,在需要的时候进行查询。
在MyBatis的属性中配置:
将lazyLoadingEnabled设置为true表示开启延迟加载,默认为false.将aggressiveLazyLoading设置为false表示按需加载,默认为true
JDBC为什么效率比MyBatis快JDBC是java提供的操作数据库的api;jdbc存在弊端:编程工作量相对较大繁琐。
MyBatis是一个支持普通SQL查询,存储过程和高级映射的持久层的框架。MyBatis封装了JDBC API,能够通过反射将JDBC与Java对象映射,基本不用写JDBC代码。
由于采用反射进行映射,性能比原生JDBC API略慢。