参考链接: 在Java中将预定义的类名用作类或变量名
花了一星期把学过的都整理一遍
尽量易懂,从基础到框架
最新版大厂面经汇总出炉,持续更新中
汇总完了上传网盘,设计到后端架构师的一切知识
如果没更新就代表我死了
一. Java基础
1. 基本数据类型
基本数据类型分为三大类:
数值型:
整数型:byte【-2^7,2^7-】,short【-2^15,2^15】,int【-2^31,2^31】,long【-2^64,2^64】
浮点型:float,double
字符型:char
布尔型:boolean
2. 基本题
2.1Java有没有goto?
java中的保留字,现在没有在java中使用。
2.2说说&和&&的区别。
&和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为true时,整个运算结果才为true,否则,只要有一方为false,则结果为false。
&&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式,例如,对于if(str != null && !str.equals(“”))表达式,当str为null时,后面的表达式不会执行,所以不会出现NullPointerException如果将&&改为&,则会抛出NullPointerException异常。If(x==33 & ++y>0) y会增长,If(x==33 && ++y>0)不会增长
&还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作,我们通常使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位,例如,0x31 & 0x0f的结果为0x01。
2.3switch语句能否作用在byte上,能否作用在long上,能否作用在String上?
在switch(expr1)中,expr1只能是一个整数表达式或者枚举常量,整数表达式可以是int基本类型或Integer包装类型,由于,byte,short,char都可以隐含转换为int,所以,这些类型以及这些类型的包装类型也是可以的。显然,long和String类型都不符合switch的语法规定,并且不能被隐式转换成int类型,所以,它们不能作用于swtich语句中。
2.4说一下"=="和equals方法究竟有什么区别?
非常经典的一个面试题?先说清楚一个,再来说另一个?
==用来判断两个变量之间的的值是否相等。变量就可以分为基本数据类型变量,引用类型。
如果是基本数据类型的变量直接比较值而引用类型要比较对应的引用的内存的首地址。
equals 用来比较两个对象长得是否一
2.5静态变量和实例变量的区别?
在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。
在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
2.6是否可以从一个static方法内部发出对非static方法的调用?
不可以。因为非static方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而static方法调用时不需要创建对象,可以直接调用。也就是说,当一个static方法被调用时,可能还没有创建任何实例对象,如果从一个static方法中发出对非static方法的调用,那个非static方法是关联到哪个对象上的呢?这个逻辑无法成立,所以,一个static方法内部不可以发出对非static方法的调用。
2.7java中实现多态的机制是什么?
靠的是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
2.8JVM
(1) 基本概念:
JVM是可运行Java代码的假想计算机 ,包括一套字节码指令集、一组寄存器、一个栈、 一个垃圾回收,堆 和 一个存储方法域。JVM 是运行在操作系统之上的,它与硬件没有直接 的交互
(2) 运行过程
我们都知道 Java 源文件,通过编译器,能够生产相应的.Class 文件,也就是字节码文件, 而字节码文件又通过Java虚拟机中的解释器,编译成特定机器上的机器码 。
也就是如下:
① Java源文件—->编译器—->字节码文件
② 字节码文件—->JVM—->机器码
每一种平台的解释器是不同的,但是实现的虚拟机是相同的,这也就是 Java 为什么能够 跨平台的原因了 ,当一个程序从开始运行,这时虚拟机就开始实例化了,多个程序启动就会 存在多个虚拟机实例。程序退出或者关闭,则虚拟机实例消亡,多个虚拟机实例之间数据不 能共享。
1. JVM 内存区域
JVM 内存区域主要分为线程私有区域【程序计数器、虚拟机栈、本地方法区】、线程共享区 域【JAVA堆、方法区】、直接内存。
线程私有数据区域生命周期与线程相同, 依赖用户线程的启动/结束 而 创建/销毁(在 Hotspot VM 内, 每个线程都与操作系统的本地线程直接映射, 因此这部分内存区域的存/否跟随本地线程的 生/死对应)。
线程共享区域随虚拟机的启动/关闭而创建/销毁。
直接内存并不是JVM运行时数据区的一部分, 但也会被频繁的使用: 在JDK 1.4引入的NIO提 供了基于 Channel 与 Buffer 的 IO 方式, 它可以使用 Native 函数库直接分配堆外内存, 然后使用 DirectByteBuffer 对象作为这块内存的引用进行操作(详见: Java I/O 扩展), 这样就避免了在 Java 堆和Native堆中来回复制数据, 因此在一些场景中可以显著提高性能。
2.9.AVA 四种引用类型
1. 强引用
在 Java 中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引 用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即 使该对象以后永远都不会被用到JVM也不会回收。因此强引用是造成Java内存泄漏的主要原因之 一。
2. 软引用
软引用需要用 SoftReference 类来实现,对于只有软引用的对象来说,当系统内存足够时它 不会被回收,当系统内存空间不足时它会被回收。软引用通常用在对内存敏感的程序中。
3. 弱引用
弱引用需要用WeakReference 类来实现,它比软引用的生存期更短,对于只有弱引用的对象 来说,只要垃圾回收机制一运行,不管JVM的内存空间是否足够,总会回收该对象占用的内存。
4. 虚引用
虚引用需要PhantomReference类来实现,它不能单独使用,必须和引用队列联合使用。虚 引用的主要作用是跟踪对象被垃圾回收的状态。
3.0JVM 类加载机制
JVM 类加载机制分为五个部分:加载,验证,准备,解析,初始化
1. 加载 加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的java.lang.Class对 象,作为方法区这个类的各种数据的入口。注意这里不一定非得要从一个Class文件获取,这里既 可以从ZIP包中读取(比如从jar包和war包中读取),也可以在运行时计算生成(动态代理), 也可以由其它文件生成(比如将JSP文件转换成对应的Class类)。
2. 验证 这一阶段的主要目的是为了确保Class文件的字节流中包含的信息是否符合当前虚拟机的要求,并 且不会危害虚拟机自身的安全。
3. 准备 准备阶段是正式为类变量分配内存并设置类变量的初始值阶段,即在方法区中分配这些变量所使 用的内存空间。注意这里所说的初始值概念,比如一个类变量定义为:
4.解析 解析阶段是指虚拟机将常量池中的符号引用替换为直接引用的过程。符号引用就是class文件中 的
5. 符号引用 符号引用与虚拟机实现的布局无关,引用的目标并不一定要已经加载到内存中。各种虚拟 机实现的内存布局可以各不相同,但是它们能接受的符号引用必须是一致的,因为符号引 用的字面量形式明确定义在Java虚拟机规范的Class文件格式中。
6. 直接引用 直接引用可以是指向目标的指针,相对偏移量或是一个能间接定位到目标的句柄。如果有 了直接引用,那引用的目标必定已经在内存中存在。
7. 初始化 初始化阶段是类加载最后一个阶段,前面的类加载阶段之后,除了在加载阶段可以自定义类加载 器以外,其它操作都由JVM主导。到了初始阶段,才开始真正执行类中定义的Java程序代码。
8. 类构造器
3.包装类型:
包装类型是对基本数据类型不足之处的补充,基本数据类型传递方式是值传递,而包装类型是引用传递,同时提供了很多数据类型间转换的方法
4.集合
List:有序,可重复的。可以通过索引快速的查找,但是进行增删操作时后续的数据需要移动,索引增删速度慢。
Set:无序,不可重复的
Map:键值对,键唯一,值不唯一。根据键得到值,对map集合遍历时先得到键的set集合,对set集合进行遍历,得到相应的值。
4.1ArrayList
1)有序表 有序,查找效率高
2)内部原理:object【】数组
3)扩容方式是原长度的1.5倍
(ArrayList 是最常用的 List 实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。数 组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要将已经有数 组的数据复制到新的存储空间中。当从 ArrayList 的中间位置插入或者删除元素时,需要对数组进 行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。)
4.2linkedList
1)链表,有序,插入和删除效率高
2)内部原理:双链表
3)默认是空节点
(LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较 慢。另外,他还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作堆 栈、队列和双向队列使用。)
4.3迭代器Iterator
1)原理:逻辑上存在用来保存数组原始地址的模型,通过移动游标获取元素的地址,从而快速的获取元素
2)作用:用于集合的遍历
4.4vector向量表
1)内部原理:object【】
2)默认空间10
3)是线程安全
4)扩容方式:扩容为原来的2倍
(Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一 个线程能够写 Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此, 访问它比访问ArrayList慢。)
4.5HashMap
1)根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度
2)遍历时,取得数据的顺序是完全随机的,因为键对象不可以重复,最多只允许一条记录的键为null,允许多条记录的值为null
3)非同步的
(HashMap根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快 的访问速度,但遍历顺序却是不确定的。 HashMap最多只允许一条记录的键为null,允许多条记 录的值为 null。HashMap 非线程安全,即任一时刻可以有多个线程同时写 HashMap,可能会导 致数据的不一致。如果需要满足线程安全,可以用 Collections 的 synchronizedMap 方法使 HashMap 具有线程安全的能力,或者使用 ConcurrentHashMap。我们用下面这张图来介绍 HashMap 的结构。
(Java8 对 HashMap 进行了一些修改,最大的不同就是利用了红黑树,所以其由 数组+链表+红黑 树 组成。
根据 Java7 HashMap 的介绍,我们知道,查找的时候,根据 hash 值我们能够快速定位到数组的 具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决 于链表的长度,为 O(n)。为了降低这部分的开销,在 Java8 中,当链表中的元素超过了 8 个以后, 会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为 O(logN)。)
4.6 HashTable
1)是线程安全的,但是效率低,支持线程同步,任意时刻只有一个线程能写HashTable
2)继承自Dictionary类,不允许记录的键或者值为null
3)同步的
(Hashtable 是遗留类,很多映射的常用功能与 HashMap 类似,不同的是它承自 Dictionary 类, 并且是线程安全的,任一时间只有一个线程能写 Hashtable,并发性不如 ConcurrentHashMap, 因为 ConcurrentHashMap 引入了分段锁。Hashtable 不建议在新代码中使用,不需要线程安全 的场合可以用HashMap替换,需要线程安全的场合可以用ConcurrentHashMap替换。)
4.7HashSet
1)内部原理是HashMap,只是应用了hashmap的key值
2)默认是空的集合
TreeSet:内部原理是TreeMap,内部实现是二叉树,插入有序,按照自然排序
(哈希表边存放的是哈希值。HashSet存储元素的顺序并不是按照存入时的顺序(和List显然不 同) 而是按照哈希值来存的所以取数据也是按照哈希值取得。元素的哈希值是通过元素的 hashcode方法来获取的, HashSet首先判断两个元素的哈希值,如果哈希值一样,接着会比较 equals方法 如果 equls结果为true ,HashSet就视为同一个元素。如果equals 为false就不是 同一个元素。
哈希值相同equals为false的元素是怎么存储呢,就是在同样的哈希值下顺延(可以认为哈希值相 同的元素放在一个哈希桶中)。也就是哈希一样的存一列。)
4.8ArrayList和LinkedList有何区别
1)ArrayList是基于动态数组的数据结构,LinkedList是基于链表的数据结构
2)ArrayList通常用来做查询,因为linkedlist要移动指针。
3)linkedlist用来做增删,因为在一个元素被插入到中间的时候, 涉及改变数组的大小,或更新索引
4)LinkedList比ArrayList消耗更多的内存,因为LinkedList中的每个节点存储了前后节点的引用。
4.9Hashmap和Hashtable的区别
1)Hashmap允许空键值,hashtable不行
2)Hashmap继承自AbstractMap,Hashtable继承自Dictionary类,两者都实现了map接口
3)Hashmap的方法不是同步的,hashtable是同步的
4)hashmap是线程不安全的效率高,hashtable是线程安全的,效率低
4.1Array和ArrayList有何不同,什么时候更适合用array
4.10Array和ArrayList有何区别?什么时候更适合用Array?
Array可以容纳基本类型和对象,而ArrayList只能容纳对象。
Array是指定大小的,而ArrayList大小是固定的。
Array没有提供ArrayList那么多功能,比如addAll、removeAll和iterator等。。
如果列表的大小已经指定,大部分情况下是存储和遍历它们。如果你要使用多维数组,使用[][]比List>更容易。
4.11栈和队列是什么,他们的区别
栈和队列都是用来存储数据的,
栈可以保存null值并且允许有重复值:push方法:将指定元素插入栈底,pop方法:弹出栈顶元素
队列表示先进后出的集合,也可以保存null值 并且允许重复:Enqueue方法:将指定元素插入队尾,Dequeue方法:队列首元素出列
4.12List和Map区别
一个是存储单列数据的集合,另一个是存储键和值这样的双列数据的集合,List中存储的数据是由顺序的,并且允许重复,Map中存储的数据是没有顺序的,其键是不能重复的,它的值是可以重复的
4.13ArrayList,vertor,LinkedList的存储性和特性
ArrayList和vertor都是使用数组方式存储数据,都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所有索引数据快而插入数据慢
Vertor由于使用synchronized方法(线程安全),通常性能上比ArrayList差
LinkedList使用双向链表实现存储,按序号索引数据需要进行前后遍历,但是插入数据时只需要记录本项的前后项即可,所有插入速度较快
LinkedList也是线程不安全的,但是他提供了一些方法,使得LinkedList可以被当做堆栈和队列来使用
4.14栈和堆的区别
栈内存是指应用程序进入一个方法时,会为这个方法单独得划分一个存储空间,,用于存储这个方法的函数和局部变量等,当这个方法结束时,这个方法中的栈会被释放,栈中的函数和局部变量等也会被释放
堆一般用于存放不放在方法栈中的数据,例如,new一个对象就是放在堆中的,所有,它不会随方法的消失而消失,方法中的局部变量被final修饰后的也是放在堆中
5.多线程
5.1多线程运行原理:
CPU在做线程的时间片切换
电脑在运行程序时不是在同时进行的。CPU复制程序的运行,而CPU在运行程序的过程中某个时间点上,它其实只能运行一个程序,cup它可以在多个线程中进行高速转换,用我们肉眼看不到的速度,每个程序就是进程,而每个进程中就会有多线程,CPU就是在 这些线程之间进行转换的
5.2线程生命周期(状态)
新建状态:一个新产生的线程从新建状态开始了它的生命周期,它保持这个状态直到程序start这个线程
运行状态:当一个新状态的线程被start之后,线程就变成了可运行状态,一个线程在此状态下被认为是开始执行线程任务
就绪状态:当一个线程等待另一个线程执行一个任务时,该线程就进入就绪状态。当另一个线程给就绪线程发送信号时,该线程重新切换到运行状态。
休眠状态:由于一个线程的时间片用完了,该线程从运行状态进入休眠状态。当时间间隔到期或者等待时间发生了,该状态的线程切换到运行状态。
终止状态:一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
5.3线程和进程的区别:
线程是进程的子集,一个进程可以有多个线程,每条线程并行执行不同的任务。
不同的进程使用的内存空间不同,而所有的线程共享一片相同的内存空间
每个线程读都拥有单独的栈内存来存储本地数据
5.4线程的几种实现方式?启动方式?区分方式?
实现方式:1.通过继承Thread类实现一个线程
继承扩展性不强,因为Java只支持单继承,如果一个类继承了thread类就不能再继承其他类了
2 实现Runnable接口
3.还可以实现callable接口
启动方式:启动线程调用start方法,启动之后再执行run方法
区分方式:thread.setName(“线程名称”),这是一种规范,在创建一个线程的完成后,都需要设置名称
5.5线程池
线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后 启动这些任务,如果线程数量超过了最大数量超出数量的线程排队等候,等其它线程执行完毕, 再从队列中取出任务来执行。他的主要特点为:线程复用;控制最大并发数;管理线程
限制线程个数,以免线程过多导致系统运行缓慢或者崩溃
线程池不需要每次使用时都去创建,节约了资源
5.6多线程的优缺点
优点:1.多线程技术使程序响应速度更快
. 2.当前没有进行处理的任务可以将处理器时间交给其他任务
3.占用大量处理时间的任务可以定期将处理器时间让给其他任务
4.可以随时停止任务
5.可以分别设置各个任务的优先级以及性能优化
缺点:1.等待使用共享资源时造成程序的运行速度变慢
2.对线程进行管理需要额外的CPU开销
3.可能出现线程死锁的情况。即较长时间的等待或资源竞争以及死锁等症状
5.7start()方法和run()
Start()方法:1.用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而继续执行下面的代码
2.通过调用thread类的start方法来启动线程,这时线程处于就绪状态,并没有运行,需要得到CPU时间片后,就开始执行run方法
Run()方法:run方法只是一个类的普通方法而已,如果直接调用run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条。
总结:1)调用start方法可启动线程
2)而run方法只是thread的一个普通方法调用,还是在主线程里执行
3)把需要并行处理的代码放在run方法中,start方法启动线程将自动调用run方法,这是JVM的内存机制规定的
4)run方法必须是public的访问权限,返回值类型是void
5.8Runnable接口和Callable接口的相同点和不同点
相同点:1.两者都是接口 2.两者都可以应用于Executors
不同点:1.Callable要实现call方法,runnable要实现run方法
2.call方法可以返回值,可以抛出异常,run方法不能
5.9怎么唤醒一个阻塞线程
如果线程是调用wait,sleep或者join方法而导致的线程阻塞,可以中断线程,并且通过抛出InterrupteException来唤醒它;如果线程遇到了IO阻塞,无能为力,因为IO是操作系统实现的,Java代码没有办法直接接触到操作系统
5.10线程安全,vector是一个线程安全类吗
如果你的代码所在的进程中有多个线程同时运行,而这些线程可能会 同时运行这段代码,如果每次运行结果和单线程运行的结果是一样的,而且其他的变量值也和预期是一样的,就是线程安全。
Vector是用同步方法来实现线程安全的,而ArrayList是线程不安全的
5.11生产者和消费者模型的作用是什么
1)通过平衡生产者的生产能力和消费者的消费能力来提示整个系统的运行效率。(这是生产者消费者模型最重要的作用)
2)触耦,这是生产者消费者附带的作用,触耦意味着生产者和消费者的联系少,联系越少越可以独自发展而不需要收到相互的制约
5.12同步和异步
实现方式:同步代码块,同步函数,lock锁
同步和异步之间的区别
异步:当一个线程访问资源时,值需要获取时间片即可,如果时间片消耗完,任务未完成 暂时将任务保存,当下一次获取时间片继续执行。 当多个线程访问资源时,每个线程只需要关注时间片即可
同步:当多个线程访问共享资源时,获取时间片的同时 , 还需要获取锁,而获取锁的线程如果任务未完成,其他线程都不能访问该资源。因为锁只有一个
区别:线程同步(安全):数据安全
线程异步:执行效率高
同步和异步有何异同:如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者在读的数据可能已经被另一个线程写到,那么这些数据就是共享数据,必须进行同步存取。当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法返回时,就应该使用异步编程,在很多情况下采用异步往往效率跟高
5.13线程的死亡
线程会以下面三种方式结束,结束后就是死亡状态。
正常结束
1. run()或call()方法执行完成,线程正常结束。
异常结束
2. 线程抛出一个未捕获的Exception或Error。 调用 stop
3. 直接调用该线程的stop()方法来结束该线程—该方法通常容易导致死锁,不推荐使用。
5.14什么是死锁
两个线程或者两个以上线程都在等待对方执行完毕才继续往下执行的时候就发生了死锁,结果就是这些程序都陷入了无限的等待中
1. 乐观锁 乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为 别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数 据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新), 如果失败则要重复读-比较-写的操作。
java 中的乐观锁基本都是通过 CAS 操作实现的,CAS 是一种更新的原子操作,比较当前值跟传入 值是否一样,一样则更新,否则失败。
2. 悲观锁 悲观锁是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人 会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会block直到拿到锁。 java中的悲观锁就是Synchronized,AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到, 才会转换为悲观锁,如RetreenLock。
3. 自旋锁 自旋锁原理非常简单,如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁 的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋), 等持有锁的线程释放锁后即可立即获取锁,这样就避免用户线程和内核的切换的消耗。
Synchronized 同步锁
synchronized 它可以把任意一个非 NULL 的对象当作锁。他属于独占式的悲观锁,同时属于可重 入锁。
Synchronized
作用范围
1. 作用于方法时,锁住的是对象的实例(this); 2. 当作用于静态方法时,锁住的是Class实例,又因为Class的相关数据存储在永久带PermGen (jdk1.8 则是 metaspace),永久带是全局共享的,因此静态方法锁相当于类的一个全局锁, 会锁所有调用该方法的线程; 3. synchronized 作用于一个对象实例时,锁住的是所有以该对象为锁的代码块。它有多个队列, 当多个线程一起访问某个对象监视器的时候,对象监视器会将这些线程存储在不同的容器中。
Synchronized
核心 组件
1) Wait Set:哪些调用wait方法被阻塞的线程被放置在这里; 2) Contention List:竞争队列,所有请求锁的线程首先被放在这个竞争队列中; 3) Entry List:Contention List中那些有资格成为候选资源的线程被移动到Entry List中; 4) OnDeck:任意时刻,最多只有一个线程正在竞争锁资源,该线程被成为OnDeck; 5) Owner:当前已经获取到所资源的线程被称为Owner; 6) !Owner:当前释放锁的线程。
5.15wait与sleep,notify的区别
1)Sleep方法来自thread类,不会释放对象锁,睡眠后不会让出资源类
2)wait方法来自object,会释放对象锁,可以让其他线程占用CPU
4)notify唤醒一个正在运行的线程处于睡眠状态,注意在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级
5.16 四种线程池
Java 里面线程池的顶级接口是 Executor,但是严格意义上讲 Executor 并不是一个线程池,而 只是一个执行线程的工具。真正的线程池接口是ExecutorService。
1. newCachedThreadPool 创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行 很多短期异步任务的程序而言,这些线程池通常可提高程序性能。调用 execute 将重用以前构造 的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并 从缓存中移除那些已有 60 秒钟未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资 源。
2. newFixedThreadPool 创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大 多数 nThreads 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务, 则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何 线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地关闭之 前,池中的线程将一直存在。
3. newScheduledThreadPool 创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
4. newSingleThreadExecutor Executors.newSingleThreadExecutor()返回一个线程池(这个线程池只有一个线程),这个线程 池可以在线程死后(或发生异常时)重新启动一个线程来替代原来的线程继续执行下去!
5.17终止线程 4 种方式
1. 正常运行结束
程序运行结束,线程自动结束。
2. 使用退出标志退出线程
一般 run()方法执行完,线程就会正常结束,然而,常常有些线程是伺服线程。它们需要长时间的 运行,只有在外部某些条件满足的情况下,才能关闭这些线程。使用一个变量来控制循环,例如: 最直接的方法就是设一个boolean类型的标志,并通过设置这个标志为true或false来控制while 循环是否退出
3. Interrupt 方法结束线程
4. stop 方法终止线程(线程不安全)
不安全主要是: thread.stop()调用之后,创建子线程的线程就会抛出 ThreadDeatherror 的错误,并且会释放子 线程所持有的所有锁。一般任何进行加锁的代码块,都是为了保护数据的一致性,如果在调用 thread.stop()后导致了该线程所持有的所有锁的突然释放(不可控制),那么被保护数据就有可能呈 现不一致性,其他线程在使用这些被破坏的数据时,有可能导致一些很奇怪的应用程序错误。因 此,并不推荐使用stop方法来终止线程
http://6.IO流
6.1对IO流的理解
IO流主要用来处理输入输出问题,常用的IO流有InputStream和OutputStream,Reader,Writer等
6.2JavaIO里常见的类,字节流,字符流,接口,实现类,方法阻塞
输入流就是从外部文件输入到内存,输出流就是从内存输出到文件
IO流主要分为字符流和字节流
字符流中有抽象类:InputStream和OutputStream,子类:FileInputStream,FileOutputStream,BufferedOutputStream等其中BufferedReader和Writer等都实现了Closeable,Flushable,Appendable这些接口。程序中的输入流输出流都是以流的形式保存的,流中保存的实际上都是字节文件。
Java中的阻塞式方法都是指在程序调用该方法时,必须等到输入数据可用或者监测到输入结束或者抛出异常,否则程序会一直停留在该语句上,不会执行下面的语句,比如read方法和readLine方法
6.3字符流和字节流的区别
底层设备永远只接受字节数据,有时候要写字符串到底层设备,需要将字符串转换成字节再进行写入,字符流是字节流的包装,字符流则是直接接受字符串,它内部将串换成字节,再写入底层设备
6.4实现一个拷贝文件的工具类使用字节流还是字符流?
我们拷贝的文件不确定是只包含字符流,有可能有字节流(图片,声音等),为考虑到通用性,要使用字节流
6.5NIO
NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector。传统IO 基于字节流和字 符流进行操作,而NIO基于 Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区 中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如:连接打开, 数据到达)。因此,单个线程可以监听多个数据通道。
NIO和传统IO 之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。
1. NIO的缓冲区
Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何 地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓 存到一个缓冲区。NIO的缓冲导向方法不同。数据读取到一个它稍后处理的缓冲区,需要时可在 缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所 有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的 数据。
2. NIO的非阻塞
IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有 一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。 NIO的非阻塞模式, 使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可 用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以 继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它 完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上 执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。
6.6字节流进行大量的从硬盘读取,要用哪个流
BufferedInputStream使用缓冲流能够减少对硬盘的伤害
6.7可序列化,如何实现可序列化
把一个对象写入数据源或者从一个数据源读出来,使用可序列化,需要实现Serizlizable接口
6.8所有的流可以分为几大类,名字各代表什么
字节输入流InputStream
字节输出流:OutputStream
字符输入流:Reader
字符输出流:Wreter
所有流都是这四个流的子类
6.9流使用什么方法关闭,在哪里关闭比较好,处理流是怎么关闭的,多个流互相调用传入怎么关闭
流一旦打开必须关闭,使用close方法,放入finally语句块中
调用处理流就关闭处理流
多个流互相调用只关闭最外层的流
6.10对象序列化,反序列化,实现对象序列化需要做哪些工作
对象序列化:将对象以二进制的形式保存在硬盘上
反序列化:将二进制的文件转换为对象读取
实现Serializable接口
6.11节点流,处理流的用处,处理流的创建有什么特征
节点流:直接与数据源相连,用于输入或输出
处理流:在节点流的基础上对之进行加工,进行一些功能的扩展
处理流的构造器必须要传入节点流的子类
6.12 阻塞 IO 模型
最传统的一种IO模型,即在读写数据过程中会发生阻塞现象。当用户线程发出IO 请求之后,内 核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用 户线程交出CPU。当数据就绪之后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除block状态。典型的阻塞IO模型的例子为:data = socket.read();如果数据没有就 绪,就会一直阻塞在read方法。
6.13非阻塞 IO 模型
当用户线程发起一个read操作后,并不需要等待,而是马上就得到了一个结果。如果结果是一个 error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦内核中的数据准备 好了,并且又再次收到了用户线程的请求,那么它马上就将数据拷贝到了用户线程,然后返回。 所以事实上,在非阻塞IO模型中,用户线程需要不断地询问内核数据是否就绪,也就说非阻塞IO 不会交出CPU,而会一直占用CPU
6.14多路复用 IO 模型
多路复用IO模型是目前使用得比较多的模型。Java NIO实际上就是多路复用IO。在多路复用IO 模型中,会有一个线程不断去轮询多个socket的状态,只有当socket真正有读写事件时,才真 正调用实际的IO读写操作。因为在多路复用IO模型中,只需要使用一个线程就可以管理多个 socket,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有 socket读写事件进行时,才会使用IO资源,所以它大大减少了资源占用。在Java NIO中,是通 过selector.select()去查询每个通道是否有到达事件,如果没有事件,则一直阻塞在那里,因此这 种方式会导致用户线程的阻塞。多路复用IO 模式,通过一个线程就可以管理多个socket,只有当 socket真正有读写事件发生才会占用资源来进行实际的读写操作。因此,多路复用IO 比较适合连 接数比较多的情况。
6.15信号驱动 IO 模型
在信号驱动IO 模型中,当用户线程发起一个IO请求操作,会给对应的socket注册一个信号函 数,然后用户线程会继续执行,当内核数据就绪时会发送一个信号给用户线程,用户线程接收到 信号之后,便在信号函数中调用IO 读写操作来进行实际的IO 请求操作。
6.16异步 IO 模型
异步IO模型才是最理想的IO 模型,在异步IO 模型中,当用户线程发起read操作之后,立刻就 可以开始去做其它的事。而另一方面,从内核的角度,当它受到一个asynchronous read之后, 它会立刻返回,说明read请求已经成功发起了,因此不会对用户线程产生任何block。然后,内 核会等待数据准备完成,然后将数据拷贝到用户线程,当这一切都完成之后,内核会给用户线程 发送一个信号,告诉它read操作完成了。也就说用户线程完全不需要实际的整个IO操作是如何 进行的,只需要先发起一个请求,当接收内核返回的成功信号时表示IO操作已经完成,可以直接 去使用数据了。
7.异常
7.1error和exception有什么区别
Error表示系统级错误,是Java运行环境内部错误或者硬件问题,不能指望程序来处理这样的问题,除了退出运行外别无选择,他是JVM抛出的
Exception表示程序需要捕捉,需要处理的异常,是由程序设计的不完善而出现的问题,程序必须处理的问题
7.2运行时异常和一般异常有何不同
Java提供了两类主要异常:runtimeException和checkedException
运行时异常:我们一般不处理,当出现这类异常时程序会由JVM接管,出现运行异常时,程序会将异常一直向上抛,一直抛到处理代码
一般异常:主要是指IO异常,SQL异常,对于这类异常,JVM要求我们必须进行cathc处理
7.3Java异常处理机制的原理
通过面向对象的方式对异常进行处理,Java把异常按照不同的类型进行分类,并提供了良好的接口,在Java中,每个异常都是一个对象,他都是Throwable,或其子类的实例,当一个方法出现异常后就会抛出一个异常对象,该对象包含异常信息,调用这个对象的方法可以捕获到这个异常并对异常进行处理
Java的异常处理是通过5个关键词来实现的:try catch,throw,throws finally
一般情况下是用try来执行一段程序,如果出现异常,系统会抛出,我们可以通过它的类型来捕获它,或最后由缺省处理器来处理它
Try:用来指定一块预防所有异常的程序
Catch:紧跟try后面,用来捕获异常
Throw:用来明确的抛出一个异常
Throws:用来标明一个成员函数可能抛出的各种异常
Finally:确保一段代码无论发生什么异常都会被执行的一段代码
7.4项目中是怎样对异常进行处理的
1)尽量避免出现runtimeException,例如对于可能出现空指针的代码,带使用对象之前一定要判断一下该对象是否为空,必要的时候对runtimeException也进行try catch 处理
2)进行try catch处理的时候要在catch代码块中对异常信息进行记录,通过调用异常类的相关方法获取到异常的相关信息,返回带web端,例如,以前做的一个项目,程序遇到异常页面会显示一个突破告诉用户哪些操作导致程序出现了什么异常,同时突破上有一个按钮用来点击展示异常的详细信息给程序员看
7.5final,finally,finalize的区别
Final:用于声明变量,方法和类,分别表示变量值不可变,方法不可覆盖,类不可以继承
Finally:是异常处理的一个关键字,表示finally里面的代码一定要执行
Finalize:是object类的一个方法,在垃圾回收的时候会调用被回收对象的此方法
8.单例模式
单例模式保证了对象唯一。分为懒汉式(在类加载的时不初始化)和饿汉式(在类加载时就完成了初始化,所有类加载比较慢,但获取对象的速度快)两种
8.1单例模式实现步骤
:私有化构造函数,创建一个静态的私有对象,提供公共的访问方法。
8.2单例模式的特点
1)某个类只能有一个实例
2)必须自制件创建这个实例
3)必须自行向整个系统提供这个实例
应用情况:对于多个对象使用同一个配置信息时,就需要保证该对象的唯一性
8.3如何保证对象的唯一性
1)不允许其他程序用new创建该类对象
2)在该类创建一个本类实例
3)对外提供一个方法让其他程序可以获取该对象
9.GC
9.1GC是什么,为什么要有GC
GC是垃圾收集的意思,负责清除对象并释放内存。Java提供的GC功能可自动检测对象是否超过作用域从而达到自动回收内存的目的,从而防止内存泄漏
9.2GC的原理
对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址,大小以及使用情况。通常GC采用有向图的方式记录和管理员中的所有对象。通过这种方式确定哪些对象是“可达的”,哪些是不可达的。当GC确定一些对象为不可达时,GC就有责任回收这些内存空间。程序员可以手动执行system。GC,通知GC运行,但是Java语言规范并不保证GC一定会执行
9.3如何确定垃圾
1.引用计数法 在 Java 中,引用和对象是有关联的。如果要操作对象则必须用引用进行。因此,很显然一个简单 的办法是通过引用计数来判断一个对象是否可以回收。简单说,即一个对象如果没有任何与之关 联的引用,即他们的引用计数都不为 0,则说明对象不太可能再被用到,那么这个对象就是可回收 对象。
2.可达性分析 为了解决引用计数法的循环引用问题,Java 使用了可达性分析的方法。通过一系列的“GC roots” 对象作为起点搜索。如果在“GC roots”和一个对象之间没有可达路径,则称该对象是不可达的。要注意的是,不可达对象不等价于可回收对象,不可达对象变为可回收对象至少要经过两次标记 过程。两次标记后仍然是可回收对象,则将面临回收。
3. 标记清除算法(Mark-Sweep)
最基础的垃圾回收算法,分为两个阶段,标注和清除。标记阶段标记出所有需要回收的对象,清 除阶段回收被标记的对象所占用的空间。如图
4.复制算法(copying)
为了解决Mark-Sweep算法内存碎片化的缺陷而被提出的算法。按内存容量将内存划分为等大小 的两块。每次只使用其中一块,当这一块内存满后将尚存活的对象复制到另一块上去,把已使用 的内存清掉
二.JavaWeb
1.Ajax
1.1什么是ajax
Ajax是异步的JavaScript和xml
原理:通过XmlHttpRequest对象来向服务器发送异步请求,从服务器获得数据,然后用JavaScript来操作DOM而更像界面。最关键的异步就是从服务器获得请求数据
XmlHttpRequest是ajax的核心机制,它是在IE5中首先引进的,是一种支持异步请求的技术。就是JavaScript可以及时向服务器提出请求和处理响应,而不阻塞用户,达到局部刷新的效果
XMLHttpRequest:是一种支持异步请求,可以使用JavaScript向服务器提出请求并处理响应。而不阻塞用户,通过这个对象,开发人员可以在页面加载以后进行页面的局部更新
1.2ajax的几种请求方式和优缺点,POST,GET
常用的post,get,delete。不常用的copy,head,link等
1) Post比get安全(因为post参数在请求体中,get参数在url上)
2) Get传输速率比post快,根据传参决定(因为post通过请求体传参,后台通过数据流接收,速度稍微慢点。而get通过url传参可以直接获取)
3) Post传输文件理论上没有限制,get传输文件大概在7-8K 左右 IE4K左右
4) Get获取数据 post上传数据
1.3ajax应用和传统web应用有什么不同
1)传统的web前端与后端的交互中,浏览器直接访问tomcat的servlet来获取数据。Servlet通过转发把数据 给浏览器
2)当我们使用ajax之后,浏览器是先把请求发送到XMLHttpRequest异步对象之中,异步对象对请求进行封装,然后再发送给服务器服务器并不是以转发的方式响应,而是以流的方式把数据返回给浏览器
3)XMLHttpRequest异步对象会不停的监听服务器状态的编号,得到服务器返回的数据,就写到浏览器上
1.4ajax的实现流程
1)创建XMLHttpRequest对象
2)创建一个新的HTTP请求,并指导该HTTP请求的方法,URL及验证信息
3)设置响应HTTP请求状态变化的函数
4)发送HTTP请求
5)获取异步调用返回的数据
6)使用JavaScript和DOM实现局部刷新
1.4jQuery的ajax和原生JS实现的ajax有什么关系
jQuery中的ajax也是通过原生的JS封装的,封装完成后让我们使用起来更加便利。不用考虑底层实现和兼容性处理
如果采用原生JS实现ajax是非常麻烦的,并且每次都是一样。如果我们不使用jQuery也要封装ajax对象的方法和属性
2. jQuery
2.1什么是jQuery
是一个JavaScript库,功能包括HTML元素选取和操作,CSS操作,HTML事件函数等,提供了大量插件
2.2jQuery选择器
1、基本选择器:直接根据id、css类名、元素名返回匹配的dom元素。
2、层次选择器:也叫做路径选择器,可以根据路径层次来选择相应的DOM元素。
3、过滤选择器:在前面的基础上过滤相关条件,得到匹配的dom元素。
2.1js和jQuery的关系
jQuery是一个JS框架,封装了JS的属性和方法,并且增强了JS的功能
使用原生JS是要处理很多兼容性问题,由于jQuery封装了底层,就不用处理这些问题了
原生的JS的DOM和事件绑定等操作麻烦
3.转发(forward)和重定向(redirect)的区别
Forward是容器中控制权的转向,是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容在发给浏览器,浏览器根部不知道服务器发送的内容是从哪儿来的,所以它的地址栏还是原来的地址
Redirect就是服务器端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,因此浏览器的地址栏中可以看到跳转后的链接地址,很明显redirect无法访问到服务器保护起来资源,但是可以从一个网站重定向到其他网站
4.转发以及如何实现转发
转发是一个 Web 组件(Servlet/JSP)将未完成的处理通过容器转交给另外一个 Web 组件
继续完成.
可以按照以下三个步骤来实现转发:
1.绑定数据到 request 对象,代码如下:
request.setAttribute(String name,Object obj);
2.获得转发器,代码如下:
RequestDispatcher rd = request.getRequestDispatcher(String uri);
3.转发,代码如下:
rd.forward(request,response);
4. Session和cookie的区别
两者都是会话跟踪技术
Session:通过服务端记录信息确定用户身份,但是session的实现依赖于cookie,session把数据放在服务器上,登录信息用session
Cookie:通过客户端记录信息确定用户身份,数据存放在客户的浏览器上,不是很安全,单个保存的数据不能超过4K,购物车最好用cookie
5. Servlet的生命周期
servlet有良好的生存期的定义,包括加载和实例化、初始化、处理请求以及服务结束。这个生存期由javax.servlet.Servlet接口的init,service和destroy方法表达。
Web容器加载servlet,生命周期开始,通过调用servlet的init方法进行servlet的初始化,通过调用service方法实现,根据不同调用不同的doget方法。结束服务,web容器调用servlet的destory方法
6. web.xml文件可以配置哪些内容
监听器,过滤器,servlet相关参数,会话超时时间,安全验证,错误页面等
7. doGet和doPost
调用 :
默认情况是调用doget方法,JSP页面中的form表单的method属性设置为post的时候,调用dopost,为get的时候调用doGet
区别:
1) get请求提交的数据会在地址栏显示出来,而post不会
2) 传输数据的大小:get请求由于浏览器对地址长度的限制导致传输的数据有限制,post不会
3) 安全性:post比get安全性高,因为数据会在地址中呈现,可以通过历史记录找到密码等关键信息
7.JSP的九大内置对象和作用
1)request:负责得到客户端请求的信息
2)response:负责向客户端 发出响应
3)session:负责保存同一个客户端一次会话过程中的一些信息
4)out:负责管理客户端的输出
5)application:表示整个应用环境的信息
6)config:表示servletConfig
7)exception:表示页面中发生的异常,可以通过它获得页面异常的信息
8)pageContext:表示这个JSP页面的上下文
9)page:表示当前JSP页面本身
8.详细描述MVC
基于Java的web应用系统采用MVC设计模型,即用Model(模型)、View(视图)和Controller(控制) 分离设计,这是目前web应用服务系统的主流设置方向
Model:处理业务逻辑的模块
View:负责页面显示,显示model的处理结果给用户,主要实现数据到页面的转换过程
Controller:负责每个请求的分发,把form数据传递给model进行处理,完成后把处理结果返回给相应的view显示给用户
9.MVC的实现技术
通过Model-View-Controlle这种设计模型把应用逻辑,处理过程和显示逻辑分成不同的组件来实现,这些组件可以交互和重用r
10.JSP和servlet的区别和联系
JSP是servlet的扩展,本质上是servlet的简易方式,更强调应用的外表表达,翻译后是类servlet
Servlet和JSP最主要的不同在于,servlet的应用逻辑在Java文件中,并且完全从表示层的HTML里分离开,而JSP的情况是Java和HTML可以组合成一股扩展名为.jsp的文件。
JSP偏重于视图
Servlet偏重于业务逻辑
11.页面间对象传递的方法
Request,session,application,cookie
12.JavaScript三种创建对象的方式
1.创建对象的实例:使用 Object 对象,并封装属性和方法;
2.创建对象的模板:定义构造函数,创建自定义对象并封装属性和方法;
3.JSON:使用 JSON 的语法创建
13Servlet 是否线程安全的,如何解决?
Servlet 存在线程安全问题.容器收到请求之后,会启动一个线程来进行相应的处
理.
默认情况下,容器只会为某个 Servlet 创建一个实例,如果同时有多个请求同时访问某
个 Servlet 则肯定会有多个线程访问同一个 Servlet 实例.如果这些线程要修改 Servlet 实
例的某个属性,就有可能发生线程安全问题.
可以使用 synchronized 对代码加锁来解决 Servlet 的安全问题
14什么是监听器
Servlet 规范中定义的一种特殊的组件,用来监听 Servlet 容器产生的事件并进行相应
的处理.
15 JSP 的四种范围
JSP 的四种范围如下:
1.page 是代表与一个页面相关的对象和属性.一个页面由一个编译好的 Java servlet
类表示.这既包括 servlet 又包括被译成 servlet 的 JSP 页面;
2.request 是代表与 Web 客户机发出的一个请求相关的对象和属性.一个请求可能跨越
多个页面,涉及多个 Web 组件;
3.session 是代表与用于某个 Web 客户机的一个用户体验相关的对象和属性.一个 Web
会话可以也经常会跨越多个客户机请求;
4.application是代表与整个Web应用程序相关的对象和属性.这实质上是跨越整个Web
应用程序,包括多个页面,请求以及会话的一个全局作用域.
16四大域对象
HttpSession:
1) 使用:调用request.getSession方法
2) 生命周期:在第一次调用requets.getSession方法时,服务器会检查是否有对应的session存在,如果没有就在内存中创建一个session并分配一个ID返回。当一段时间内session没有被使用(默认是30分钟),则服务器会销毁session。如果服务器被非正常关闭,没有到期的session也会被跟着销毁,如果调用invalidate()方法,可以立即销毁session
ServletRequest:
1) 使用:调用request方法
2) 在service方法调用前由服务器创建,传入service方法。整个请求结束,request生命结束
ServletContext:
1)使用:request.getSession().getServletContext
2)什么周期:当web应用被加载进容器时创建代表整个web应用的servletContext对象,存在于全局当中,当服务器关闭或web应用被移除时,生命周期结束
PageContext:
当jsp请求时开始,响应结束后销毁
三.数据库
关键字:
1)连接查询:内连接,外连接,自然连接,交叉连接
内连接:基本语法:坐标【inner】join右表on左表.字段 = 右表.字段
从左表中取出每一条记录,去右表中所有的记录进行匹配
外连接:左边left/right join 右表 on 左表.字段 = 右表.字段
Left join:左外连接,以左表为主表
Right join:右外连接,以右表为主表
2)索引:索引(Index)是帮助 MySQL 高效获取数据的数据结构。常见的查询算法,顺序查找,二分查找,二 叉排序树查找,哈希散列法,分块查找,平衡多路搜索树B树
常见索引原则有
1. 选择唯一性索引
唯一性索引的值是唯一的,可以更快速的通过该索引来确定某条记录。
2. 为经常需要排序、分组和联合操作的字段建立索引 :
3 .为常作为查询条件的字段建立 索引 。
4 .限制索引的数目:
越多的索引,会使更新表变得很浪费时间。
尽量使用数据量少的索引
6. 如果索引的值很长,那么查询的速度会受到影响。
尽量使用前缀来索引
7. 如果索引字段的值很长,最好使用值的前缀来索引。
8.删除不再使用或者很少使用的索引
9. 最左前缀匹配原则,非常重要的原则。
10 . 尽量选择区分度高的列作为索引
区分度的公式是表示字段不重复的比例
11 . 索引列不能参与计算,保持列“干净”:带函数的查询不参与索引。
12 . 尽量的扩展索引,不要新建索引
3)数据库引擎:InnoDB:支持事务处理,支持外键,支持崩溃修复能力和并发控制。如果需要对事务的完整性要求比较高(比如银行),要求实现并发控制(比如售票),那选择 InnoDB 有很大的优势。如果需要频繁的更新、删除操作的数据库,也可以选择 InnoDB,因为支持事务的提交(commit)和回滚(rollback)。
MyISAM:插入数据快,空间和内存使用比较低。如果表主要是用于插入新记录和读出记录,那么选择 MyISAM 能实现处理高效率。如果应用的完整性、并发性要求比较低,也可以使用。
MEMORY:所有的数据都在内存中,数据的处理速度快,但是安全性不高。如果需要很快的读写速度,对数据的安全性要求较低,可以选择 MEMOEY。它对表的大小有要求,不能建立太大的表。所以,这类数据库只使用在相对较小的数据库表。
4) 存储过程:
一组为了完成特定功能的 SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次 编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过 程是数据库中的一个重要对象
存储过程优化思路:
1. 尽量利用一些sql语句来替代一些小循环,例如聚合函数,求平均函数等。查找语句尽量不要放在循环内。
2. 中间结果存放于临时表,加索引。
3. 少使用游标。
4. 事务越短越好。sqlserver 支持并发操作。如果事务过多过长,或者隔离级别过高,都会造成 并发操作的阻塞,死锁。导致查询极慢,cpu占用率极低。
5. 使用try-catch处理错误异常。
5)MySQL的默认连接数是100;
3.1JDBC编程的步骤
1)注册驱动
2)获取连接对象connection
3)创建statement对象
4)运行SQL语句
5)处理结果
6)关闭链接释放资源
3.2事务,事务的ACID是什么,事务并发会产生什么问题
事务就是被绑定在一起作为一个逻辑单元的SQL语句
ACID表示事务:原子性,隔离性,一致性,持久性
原子性:事务中的各项操作要么全做要么全部做,任何一项操作的失败都会导致整个事务的失败
隔离性:并发执行的事务无法彼此看到对方的状态
一致性:事务结束后系统状态是一致的
持久性:事务完成后所做的改动都会被持久化,即使灾难性的失败,通过日志和同步备份都可以在故障发生后重建数据
事务并发会产生:脏读,幻读,不可重复读
脏读:A事务读取B事务尚未提交的数据并在此基础上操作,而B事务执行回滚,那么A读取到的数据就是脏数据
幻读:事务A重新执行一个查询,返回一系列符合查询条件的行,发现其中插入了被事务B提交的行
不可重复读:事务A重新读取前面读取过的数据,发现该数据已经被另一个以提交的事务B修改过
3.3事务的隔离级别
1) READ UNCOMMITTED 幻读,不可重复读和脏读都允许.
2) READ COMMITTED 允许幻读,不可重复读,不允许脏读
3) REPEATABLE READ 允许幻读,不允许不可重复读和脏读
4) SERIALIZABLE 幻读,不可重复读和脏读都不允许
3.4分页查询
MySQL是使用关键字limit来进行也的,offset,size表示从多少索引去多少位
语句select * from t_employee limit 20,20;
Oracle分页是使用三层嵌套的语句:SELECT * FROM( SELECT A.*,ROWNUM RN FROM(SELECT * FROM t_employee) A WHERE ROWNUM <=40 ) WHERE RN >= 21
3.5数据库优化
SQL优化:
1) 尽量避免使用select *
2) 只查询一条子记录时使用limit 1
3) 使用连接查询代替子查询
4) 尽量使用一些能通过索引查询的关键字
表结构优化:
1) 尽量使用数字类型字段,提高比对效率
2) 长度不变且查询速率要求比较高的数据可用考虑使用char,否则使用varchar
其他优化:
1) 对查询频率高的字段适当建立索引,提高效率,根据表的用途适当选择数据库引擎,读写分离
3.6数据库的三范式
第一范式的目标是确保每列的原子性:如果每列都是不可再分的最小数据单元(也称为最小的原子 单元),则满足第一范式(1NF)
首先满足第一范式,并且表中非主键列不存在对主键的部分依赖。 第二范式要求每个表只描述一 件事情。
第三范式定义是,满足第二范式,并且表中的列不存在对非主键列的传递依赖。除了主键订单编 号外,顾客姓名依赖于非主键顾客编号。.
3.7数据库连接池
1)限制数据库的字数,不会导致由于数据库连接过多而系统崩溃或者运行缓慢
2)数据库连接不需要每次都去创建或销毁,节约了资源
3)响应时间更快
3.8触发器
触发器就是一种特殊的存储过程,主要是通过事件来触发而被执行的。它可以强化约束,来维护数据的完整性和一致性,可以跟踪数据库内的操作从而不允许未经许可的更新和变化,可以联机运算
使用场景:比如校内网、开心网、Facebook,你发一个日志,自动通知好友,其实就是在增加日志时做一个后触发,再向通知表中写入条目。因为触发器效率高。而UCH没有用触发器,效率和数据处理能力都很低。
03.9索引的作用和优缺点
索引就是一种特殊的查询表,数据库的搜索引擎可以利用它加速对数据的检索,索引可以是唯一的,创建索引允许指定单个列或者是多个行。缺点是它减慢了数据录入的速度,同时也增加了数据库的尺寸大小
3.10视图和游标是什么
视图:是一种虚拟的表,具有和物理表相同的功能,可以对视图进行增,该,查等操作,视图通常是由一个表或者多个表的行或列的子集,对视图的修改不影响基本表,它使我们获取数据更容易
游标:是对查询出来的结果集作为一个单元来有效的处理,游标可以定在该单元中的特定行,从结果集的当前检索一行或多行,可以对结果集当前行做修改,一般不使用游标,但是需要逐条处理数据时候,游标很重要
3.11数据库并发策略
1. 乐观锁 乐观锁认为一个用户读数据的时候,别人不会去写自己所读的数据;悲观锁就刚好相反,觉得自 己读数据库的时候,别人可能刚好在写自己刚读的数据,其实就是持一种比较保守的态度;时间 戳就是不加锁,通过时间戳来控制并发出现的问题。
2. 悲观锁 悲观锁就是在读取数据的时候,为了不让别人修改自己读取的数据,就会先对自己读取的数据加 锁,只有自己把数据读完了,才允许别人修改那部分数据,或者反过来说,就是自己修改某条数 据的时候,不允许别人读取该数据,只有等自己的整个事务提交了,才释放自己加上的锁,才允 许其他用户访问那部分数据。
3. 时间戳 时间戳就是在数据库表中单独加一列时间戳,比如“TimeStamp”,每次读出来的时候,把该字 段也读出来,当写回去的时候,把该字段加1,提交之前 ,跟数据库的该字段比较一次,如果比数 据库的值大的话,就允许保存,否则不允许保存,这种处理方法虽然不使用数据库系统提供的锁 机制,但是这种方法可以大大提高数据库处理的并发量,
以上悲观锁所说的加“锁”,其实分为几种锁,分别是:排它锁(写锁)和共享锁(读锁)。
3.12数据库锁
1. 行级锁 行级锁是一种排他锁,防止其他事务修改此行;在使用以下语句时,Oracle会自动应用行级锁:
1. INSERT、UPDATE、DELETE、SELECT … FOR UPDATE [OF columns] [WAIT n | NOWAIT]; 2. SELECT … FOR UPDATE语句允许用户一次锁定多条记录进行更新 3. 使用COMMIT或ROLLBACK语句释放锁。
2. 表级锁 表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分 MySQL 引擎支持。最常使 用的 MYISAM 与 INNODB 都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁 (排他锁)。
3. 页级锁 页级锁是 MySQL 中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级 冲突少,但速度慢。所以取了折中的页级,一次锁定相邻的一组记录。BDB支持页级锁
四.框架
1.spring
1.1spring的理解
IOC和DI的区别:
IOC是控制反转,指将对象的创建权,反转到spring容器
DI是依赖注入,指spring创建对象的过程中,将对象依赖属性通过配置进行注入
Spring是一个IOC和AOP容器框架,主要核心是:
1) 控制反转(IOC):Spring 通过一个配置文件描述 Bean 及 Bean 之间的依赖关系,利用 Java 语言的反射功能实例化 Bean 并建立 Bean 之间的依赖关系。 Spring 的 IoC 容器在完成这些底层工作的基础上,还提供 了 Bean 实例缓存、生命周期管理、 Bean 实例代理、事件发布、资源装载等高级服务。
2) 依赖注入(DI):spring使用javaBean对象的set方法或者带参数的构造方法,为创建所需对象时将属性自动设置所需要的值的过程。
3) 面向切面编程(AOP):在面向对象编程中(OOP),我们将事务纵向抽象成一个个对象。而在面向切面编程中,我们将一个个对象某些类似方法横向抽象成一个切面,对这个切面进行一些如权限验证,事务管理,记录日志等公用操作处理
在spring中,所有管理的对象都是Javabean对象,而在beanfactory和ApplicationContext就是spring框架的两个IOC容器,现在一般使用ApplicationContext,其不包含beanfactory的作用,同时进行更多的扩展
1.2spring Bean生命周期
Spring的生命周期:在配置
Bean生命周期:
1)spring容器从XML文件读取bean的定义,并实例化bean
2)spring根据bean的定义填充所有实例
3)如果bean实现了BeanNameAware接口,spring传递bean的ID到setBeanName方法
4)如果bean实现了BeanFactoryAware接口,spring传递beanfactory给setBeanFactory方法
5)如果有任何与bean相关联的BeanPostProcessors,spring会在postProcessesBeforeInitialization方法调用他们
6)如果bean实现了InitializingBean了,调用它的afterPropertySet方法,如果bean声明了初始化,调用初始化方法
7)如果有BeanPostProcessors和bean关联,这些bean的postProcessAfterInitialization方法将被调用
8)如果bean实现了DisposableBean,它将调用destory方法注意:
有两个重要的 bean 生命周期方法,第一个是 setup() , 它是在容器加载 bean 的时候被调用。第二个方法是 teardown() 它是在容器卸载类的时候被调用。
The bean 标签有两个重要的属性 init-method 和 destroy-method。使用它们你可以自己定制初始化和注销方法。它们也有相应的注解@PostConstruct 和@PreDestroy。
1.3spring注解
如下配置:
Context:annotion-config标签
1)@Required:该注解应用于设方法
2)@Autowried:该注解应用于有值设值方法,非设值方法,构造方法和变量
3)Qualifier:该注解和@Autowired注解搭配使用,用于消除特点bean自动装配的歧义
1.4spring事务
1)编程式事务管理:通过编程的方式管理事务,带来更大的灵活性,但难维护
2)声明式事务管理:可以将业务代码和事务管理分离,只需用注解和XML配置来管理事务
事务配置示例:
1.5spring事务的隔离级别
1) READ UNCOMMITTED 幻读,不可重复读和脏读都允许.
2) READ COMMITTED 允许幻读,不可重复读,不允许脏读
3) REPEATABLE READ 允许幻读,不允许不可重复读和脏读
4) SERIALIZABLE 幻读,不可重复读和脏读都不允许
1.6BeanFactory接口和ApplicationContext接口的区别
1)ApplocationContext接口继承了BeanFactory,spring的核心工厂是BeanFactory,BeanFactory采用延时加载,第一个getBean时才会初始化Bean,ApplicationContext是会在加载配置文件时初始化Bean
2)ApplicationContext是对BeanFactory的扩展,可以进行国际化处理,事务传递和Bean自动装配以及各种不同应用层的Context实现,开发中基本都使用Application,web项目中使用WebApplictionContext,很少使用beanfactory
1.7spring配置bean实例化的三种方式
1)使用类构造器(默认无参数)
2) 使用静态工厂(简单工厂模式)
//下面这段配置的含义:调用Bean2Factory的getBean2方法得到bean2
3) 使用实例化工厂(工厂方法模式)
//先创建工厂实例bean3Facory,再通过工厂实例创建目标bean实例
1.8bean注入的3种方式
1)接口注入
2)构造器注入:通过
3)set注入:通过
1.9 Spring 依赖注入四种方式
1.构造器注入
(/*带参数,方便利用构造器进行注入*/ public CatDaoImpl(String message){ this. message = message; }
2. setter方法 注入
通过
3. 静态工厂注入
静态工厂顾名思义,就是通过调用静态工厂的方法来获取自己需要的对象,为了让 spring 管理所 有对象,我们不能直接通过"工程类.静态方法()"来获取对象,而是依然通过 spring 注入的形式获 取
4. 实例工厂
实例工厂的意思是获取对象实例的方法不是静态的,所以你需要首先 new 工厂类,再调用普通的 实例方法
2.0 5 种不同方式的自动装配
Spring装配包括手动装配和自动装配,手动装配是基于 xml装配、构造方法、setter方法等
自动装配有五种自动装配的方式,可以用来指导Spring容器用自动装配方式来进行依赖注入。
1. no:默认的方式是不进行自动装配,通过显式设置ref 属性来进行装配。
2. byName:通过参数名 自动装配,Spring容器在配置文件中发现bean的autowire属性被设 置成byname,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。
3. byType:通过参数类型自动装配,Spring 容器在配置文件中发现 bean 的 autowire 属性被 设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多 个bean符合条件,则抛出错误。
4. constructor:这个方式类似于 byType, 但是要提供给构造器参数,如果没有确定的带参数 的构造器参数类型,将会抛出异常。
5. autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。
2.1 Spring APO 原理
AOP主要应用场景有
1. Authentication 权限 2. Caching 缓存 3. Context passing 内容传递 4. Error handling 错误处理 5. Lazy loading 懒加载 6. Debugging 调试 7. logging, tracing, profiling and monitoring 记录跟踪 优化 校准 8. Performance optimization 性能优化 9. Persistence 持久化 10. Resource pooling 资源池 11. Synchronization 同步 12. Transactions 事务
2. AOP 核心概念 1、切面(aspect):类是对物体特征的抽象,切面就是对横切关注点的抽象
2、横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点。
3、连接点(joinpoint):被拦截到的点,因为 Spring 只支持方法类型的连接点,所以在 Spring 中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器。
4、切入点(pointcut):对连接点进行拦截的定义
5、通知(advice):所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、 异常、最终、环绕通知五类。
6、目标对象:代理的目标对象
7、织入(weave):将切面应用到目标对象并导致代理对象创建的过程
8、引入(introduction):在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法 或字段
AOP 两种代理方式
JDK动态 接口 代理
1. JDK 动态代理主要涉及到 java.lang.reflect 包中的两个类:Proxy 和 InvocationHandler。 InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类 的代码,动态将横切逻辑和业务逻辑编制在一起。Proxy 利用 InvocationHandler 动态创建 一个符合某一接口的实例,生成目标类的代理对象。
2. CGLib
动态代理
CGLib全称为Code Generation Library,是一个强大的高性能,高质量的代码生成类库, 可以在运行期扩展 Java 类与实现 Java 接口,CGLib 封装了 asm,可以再运行期动态生成新 的 class。和 JDK 动态代理相比较:JDK 创建代理有一个限制,就是只能为接口创建代理实例, 而对于没有通过接口定义业务方法的类,则可以通过CGLib创建动态代理。
2.springMVC
2.1springMVC的执行流程
1)用户发送请求到前端控制器
2)前端控制器收到请求后调用处理器映射器
3)处理器映射器找到具体的处理器,生成处理器对象及拦截器一起返回给给前端控制器
4)前端控制器调用处理器适配器
5)处理器适配器经过适配调用具体的处理器
6)处理器执行完成返回ModelAndView对象
7)处理器适配器将controller执行结果ModelAndView返回给前端控制器
8)前端控制器将ModelAndView传给视图解析器
9)视图解析器解析后返回具体的view
10)前端控制器根据view进行视图渲染
11)前端控制器响应用户
2.2springMVC的优点
1)可以支持各种视图技术,而不仅仅局限于JSP
2)与spring框架集成(IOC容器,AOP等)
3)清晰的角色分配:前端控制器,处理器映射器,处理器适配器,视图解析器
4)支持各种请求资源的映射策略
2.3springMVC的主要组件
1)前端控制器(不需要程序员开发)
2)处理器映射器(不需要程序员开发)
3)处理器适配器
4)视图解析器(不需要程序员开发)
5)处理器(需要程序员开发)
6)视图(需要程序员开发JSP)
2.4springMVC设定转发和重定向
1)转发:在返回值前面加forward,例如:forward:user.do?name=method
2)重定向:在返回值前面加redirect,例如:redirect:http://www.baidu.caom
2.5springMVC和Struts对比
机制:SpringMVC的入口是servlet,而Struts是filter
性能:spring比Struts快一点。SpringMVC是基于方法的设计,Struts是基于类,
参数传递:Struts是在接受参数的时候,可以用属性来接受参数,参数是让多个方法共享的
设计思想:Struts更符合OOP的编程思想,spring比较严谨,在servlet上扩展
2.6springMVC和ajax的相互调用
1)加入Jackson.jar
2)在配置文件中配置json的映射
3)在接受ajax方法里面可以直接返回object,list等,但在方法前面要加数@ResponseBody注解
2.7springMVC的post和get请求乱码问题
1)post:在web.xml中配置一个CharacterEncodingFilter过滤器,设置为utf-8
2)get:修改tomcat配置文件添加编码与工程编码一致,或对参数重新进行编译
2.8SpringMVC的异常处理
可以把异常抛给Spring,由Spring框架处理;我们只需要配置简单的异常处理器,在异常处理器中添加视图页面即可
2.9SpringMVC常用的注解
1)@RequestMapping:用于处理请求URL映射的注解,可用在类和方法上。用在类上,则表示类中的所有响应请求的方法都是以该地址作为父路径
2)@RequestBody:接受http请求的json数据,将json转换为Java数据
3)@ResponseBody:将conreoller方法返回对象转化为json对象响应给客户
2.10SpringMVC的控制器注解一般使用哪个
一般用@Conntroller注解,表示在表现层,不能用别的注解代替
2.11拦截请求中,拦截get方式提交的方法
可以在@RequestMapping注解加上method=RequestMapping.get
2.12方法里得到request和session
直接在方法的形参上声明request,SpringMVC就自动把request对象传入
2.13SpringMVC的函数返回值
函数返回值有很多类型,例如:string,modelAndView。ModelAndView类把视图和数据合并到一起,但一般使用string就行
2.14拦截的方法里得到从前台传入的参数
直接在形参里声明这个参数,名字必须和传过来的参数名一样
2.15SpringMVC从后台向前台传递数据
通过ModelMap对象,可以在这个对象里调用put方法,把对象加到里面,前台就可以通过el表达式拿到
2.16ModelMap数据放入session里
可以在类上面加上@SessionAttributes注解,里面包含的字符串就是要放入session里面的key
2.17SpringMVC的拦截器写法
1)实现HandlerInterceptor接口
2)继承适配器类,然后再接口方法中,实现处理逻辑,然后再配置文件中配置拦截器就行
2.15注解原理
注解本质是继承了Annotation的特殊接口,具体实现类是Java运行时生成的动态代理类。通过反射获取注解时,返回的是Java运行时生成的动态代理对象,通过代理对象调用自定义注解的方法,最终调用invoke方法。
2.16拦截器和过滤器的区别
1、拦截器是基于java反射机制的, 不依赖于servlet容器。只能对Action请求起作用,可以访问Action上下文、值栈里的对象,在Action的生命周期中,拦截器可以多次调用2、过滤器是基于函数回调的,依赖于servlet容器,过滤器则可以对几乎所有请求起作用。只能在容器初始化时被调用一次
3.Mybatis
支持定制化SQL,存储过程以及高级映射的优秀持久层框架。Mybatis几乎避免了所有的JDBC代码和手工设置参数以及抽取结果集。使用简单的XML或注解来配置和映射基本体,将接口和Java的POJOS映射成数据库中的记录
3.1Mybatis的优点
2)简单易学。本身小且简单,没有第三方的依赖
2)灵活,不会对应用程序或者数据库的现有设计强加影响
3)解除SQL与程序代码耦合
4)提供XML标签,支持编写动态SQL
5)提供对象关系映射标签
3.2mybatis缓存
1)一级缓存:一级缓存的作用域是session,当openSession后,如果执行相同的SQL,mybatis不进行执行SQL,而是从缓存中返回
2)二级缓存:作用域是一个mapper的nameSpace,同一个nameSpace中查询SQL可以从缓存中命中。二级缓存可以跨session
3.3mybatis的编程步骤
1)创建sqlsessionFactory
2)通过SqlsessionFactory创建SqlSession
3)通过Sqlsession执行数据库操作
4)调用session.commit方法提交事务
5)调用session.close关闭会话
3.4mapper编写的几种方式
1)接口实现类继承SqlSessionDaoSupport:在SqlMapConfig.xml中配置mapper.xml的位置,然后定义mapper接口,实现类继承SqlSessionDaoSupport
2)使用mapper扫描器
3.5Mybatis动态sql
Mybatis动态sql可以在Xml映射文件内,以标签的形式编写动态sql,执行原理是根据表达式的值 完成逻辑判断并动态拼接sql的功能。
Mybatis提供了9种动态sql标签:trim | where | set | foreach | if | choose | when | otherwise | bind。
3.6MyBatis与Hibernate有哪些不同?
(1)Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。
(2)Mybatis直接编写原生态sql,可以严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql映射文件,工作量大。
(3)Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate开发可以节省很多代码,提高效率。
3.7Mybatis是如何进行分页的?分页插件的原理是什么?
Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页。可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。
3.8为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?
Hibernate属于全自动ORM映射工具,使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM映射工具。
3.9简述 MyBatis 的体系结构
MyBatis 体系结构主要由以下几个关键部分;
1.加载配置
配置有两种形式,一种是 XML 配置文件,另一种是 Java 代码的注解.MyBatis 将 SQL 的配
置信息加载成为一个个的MappedStatement对象(包括了传入参数映射配置,执行的SQL语句,
结果映射配置),并将其存储在内存中.
2.SQL 解析
当 API 接口层接收到调用请求时,会接收到传入 SQL 的 ID 和传入对象(可以使
Map,JavaBean 或者基本数据类型),MyBatis 会根据 SQL 的 ID 找到对应的 MappedStatement,
然后根据传入参数对象对 MappedStatement 进行解析,解析后可以得到最终要执行的 SQL 语
句和参数.
3.SQL 执行
将最终得到的 SQL 和参数拿到数据库进行执行,得到操作数据库的结果.
4.结果映射
将操作数据库的结果按照映射的配置进行转换,可以转换成 HashMap,JavaBean 或者基
本数据类型,并将最终结果返回.
3.10 ORM
对象关系映射(ORM),是为了解决面向对象与关系型数据库存在不匹配的技术。
通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。
ORM可以采用映射元数据来描述对象关系的映射,使得ORM中间件能在任何一个应用的业务逻辑层和数据库层之间当桥梁。Java典型的ORM框架有:Hibernate,ibatis(mybatis),speedframework。
ORM的方法论基于三个核心原则:
1) 简单:以最基本的形式建模数据
2) 传达性:数据库结构被任何人都能理解的语言文档化
3) 精确性:基于数据模型创建正确标准化了的结构
4.SpringBoot
.4.1原理
1. 创建独立的 Spring 应用程序
2. 嵌入的 Tomcat,无需部署 WAR 文件
3. 简化 Maven 配置
4. 自动配置 Spring
5. 提供生产就绪型功能,如指标,健康检查和外部配置
6. 绝对没有代码生成和对 XML 没有要求配置 [1]
4.2 JPA 原理
1. 事务 事务是计算机应用中不可或缺的组件模型,它保证了用户操作的原子性 ( Atomicity )、一致性 ( Consistency )、隔离性 ( Isolation ) 和持久性 ( Durabilily )。
2. 本地事务 紧密依赖于底层资源管理器(例如数据库连接 ),事务处理局限在当前事务资源内。此种事务处理 方式不存在对应用服务器的依赖,因而部署灵活却无法支持多数据源的分布式事务
5.SSM框架搭建
1.建maven web项目。导入maven需要引入的JAR包
2. 建立JDBC属性文件,建立spring-mybatis.xml配置文件,再进行Log4j的配置,进行Junit测试,创建测试用表,利用MyBatis Generator自动创建代码
建立service接口和实现类,建立测试类,整合springMVC,配置springMVC.xml,配置web.xml文件,新建JSP页面进行测试,建立UserController类,最后部署项目
整理不易,给个赞吧。。。
日后还会不断完善