网站建设时怎么购买空间,不用服务器做网站,深圳建设银行网站首页,北京专业做网站设计公司参考链接#xff1a; 在Java中将预定义的类名用作类或变量名
花了一星期把学过的都整理一遍 尽量易懂#xff0c;从基础到框架 最新版大厂面经汇总出炉#xff0c;持续更新中 汇总完了上传网盘#xff0c;设计到后端架构师的一切知识 如果没更新就代表我死了 一#xff0…参考链接 在Java中将预定义的类名用作类或变量名
花了一星期把学过的都整理一遍 尽量易懂从基础到框架 最新版大厂面经汇总出炉持续更新中 汇总完了上传网盘设计到后端架构师的一切知识 如果没更新就代表我死了 一 Java基础 1. 基本数据类型 基本数据类型分为三大类 数值型 整数型byte【-2^72^7-】short【-2^15,2^15】int【-2^31,2^31】long【-2^64,2^64】 浮点型floatdouble 字符型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(x33 y0) y会增长If(x33 y0)不会增长 还可以用作位运算符当操作符两边的表达式不是boolean类型时表示按位与操作我们通常使用0x0f来与一个整数进行运算来获取该整数的最低4个bit位例如0x31 0x0f的结果为0x01。 2.3switch语句能否作用在byte上能否作用在long上能否作用在String上? 在switchexpr1中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. 类构造器client 初始化阶段是执行类构造器client方法的过程。client方法是由编译器自动收集类中的类变 量的赋值操作和静态语句块中的语句合并而成的。虚拟机会保证子client方法执行之前父类 的client方法已经执行完毕如果一个类中没有对静态变量赋值也没有静态语句块那么编译 器可以不为这个类生成client()方法。 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有何区别 1ArrayList是基于动态数组的数据结构LinkedList是基于链表的数据结构 2ArrayList通常用来做查询因为linkedlist要移动指针。 3linkedlist用来做增删因为在一个元素被插入到中间的时候 涉及改变数组的大小或更新索引 4LinkedList比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等。。 如果列表的大小已经指定大部分情况下是存储和遍历它们。如果你要使用多维数组使用[][]比ListList更容易。 4.11栈和队列是什么他们的区别 栈和队列都是用来存储数据的 栈可以保存null值并且允许有重复值push方法将指定元素插入栈底pop方法弹出栈顶元素 队列表示先进后出的集合也可以保存null值 并且允许重复Enqueue方法将指定元素插入队尾Dequeue方法队列首元素出列 4.12List和Map区别 一个是存储单列数据的集合另一个是存储键和值这样的双列数据的集合List中存储的数据是由顺序的并且允许重复Map中存储的数据是没有顺序的其键是不能重复的它的值是可以重复的 4.13ArrayListvertor,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的内存机制规定的 4run方法必须是public的访问权限返回值类型是void 5.8Runnable接口和Callable接口的相同点和不同点 相同点1.两者都是接口 2.两者都可以应用于Executors 不同点1.Callable要实现call方法runnable要实现run方法 2.call方法可以返回值可以抛出异常run方法不能 5.9怎么唤醒一个阻塞线程 如果线程是调用waitsleep或者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 ListContention List中那些有资格成为候选资源的线程被移动到Entry List中 4) OnDeck任意时刻最多只有一个线程正在竞争锁资源该线程被成为OnDeck 5) Owner当前已经获取到所资源的线程被称为Owner 6) !Owner当前释放锁的线程。 5.15wait与sleepnotify的区别 1Sleep方法来自thread类不会释放对象锁睡眠后不会让出资源类 2wait方法来自object会释放对象锁可以让其他线程占用CPU 4notify唤醒一个正在运行的线程处于睡眠状态注意在调用此方法的时候并不能确切的唤醒某一个等待状态的线程而是由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.5finalfinallyfinalize的区别 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 常用的postgetdelete。不常用的copyheadlink等 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异步对象之中异步对象对请求进行封装然后再发送给服务器服务器并不是以转发的方式响应而是以流的方式把数据返回给浏览器 3XMLHttpRequest异步对象会不停的监听服务器状态的编号得到服务器返回的数据就写到浏览器上 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的实现依赖于cookiesession把数据放在服务器上登录信息用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的九大内置对象和作用 1request负责得到客户端请求的信息 2response负责向客户端 发出响应 3session负责保存同一个客户端一次会话过程中的一些信息 4out负责管理客户端的输出 5application表示整个应用环境的信息 6config表示servletConfig 7exception表示页面中发生的异常可以通过它获得页面异常的信息 8pageContext表示这个JSP页面的上下文 9page表示当前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.页面间对象传递的方法 Requestsessionapplicationcookie 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处理错误异常。 5MySQL的默认连接数是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来进行也的offsetsize表示从多少索引去多少位 语句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 控制反转IOCSpring 通过一个配置文件描述 Bean 及 Bean 之间的依赖关系利用 Java 语言的反射功能实例化 Bean 并建立 Bean 之间的依赖关系。 Spring 的 IoC 容器在完成这些底层工作的基础上还提供 了 Bean 实例缓存、生命周期管理、 Bean 实例代理、事件发布、资源装载等高级服务。 2 依赖注入DIspring使用javaBean对象的set方法或者带参数的构造方法为创建所需对象时将属性自动设置所需要的值的过程。 3 面向切面编程AOP在面向对象编程中OOP我们将事务纵向抽象成一个个对象。而在面向切面编程中我们将一个个对象某些类似方法横向抽象成一个切面对这个切面进行一些如权限验证事务管理记录日志等公用操作处理 在spring中所有管理的对象都是Javabean对象而在beanfactory和ApplicationContext就是spring框架的两个IOC容器现在一般使用ApplicationContext其不包含beanfactory的作用同时进行更多的扩展 1.2spring Bean生命周期 Spring的生命周期在配置bean元素通过init-method指定bean的初始化方法通过desstroy-method指定bean销毁方法 Bean生命周期 1spring容器从XML文件读取bean的定义并实例化bean 2spring根据bean的定义填充所有实例 3如果bean实现了BeanNameAware接口spring传递bean的ID到setBeanName方法 4如果bean实现了BeanFactoryAware接口spring传递beanfactory给setBeanFactory方法 5如果有任何与bean相关联的BeanPostProcessorsspring会在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标签 1Required:该注解应用于设方法 2Autowried:该注解应用于有值设值方法非设值方法构造方法和变量 3Qualifier:该注解和Autowired注解搭配使用用于消除特点bean自动装配的歧义 1.4spring事务 1编程式事务管理通过编程的方式管理事务带来更大的灵活性但难维护 2声明式事务管理可以将业务代码和事务管理分离只需用注解和XML配置来管理事务 事务配置示例 1.5spring事务的隔离级别 1) READ UNCOMMITTED 幻读,不可重复读和脏读都允许. 2) READ COMMITTED 允许幻读,不可重复读,不允许脏读 3) REPEATABLE READ 允许幻读,不允许不可重复读和脏读 4) SERIALIZABLE 幻读,不可重复读和脏读都不允许 1.6BeanFactory接口和ApplicationContext接口的区别 1ApplocationContext接口继承了BeanFactoryspring的核心工厂是BeanFactoryBeanFactory采用延时加载第一个getBean时才会初始化BeanApplicationContext是会在加载配置文件时初始化Bean 2)ApplicationContext是对BeanFactory的扩展可以进行国际化处理事务传递和Bean自动装配以及各种不同应用层的Context实现开发中基本都使用Applicationweb项目中使用WebApplictionContext很少使用beanfactory 1.7spring配置bean实例化的三种方式 1使用类构造器默认无参数 bean idbean1 classcn.itcast.spring.b_instance.Bean1/bean 2 使用静态工厂简单工厂模式 //下面这段配置的含义调用Bean2Factory的getBean2方法得到bean2 bean idbean2 classcn.itcast.spring.b_instance.Bean2Factory factory-methodgetBean2 /bean 3 使用实例化工厂工厂方法模式 //先创建工厂实例bean3Facory再通过工厂实例创建目标bean实例 beanidbean3Factory classcn.itcast.spring.b_instance.Bean3Factory/bean bean idbean3 factory-beanbean3Factory factory-methodgetBean3/bean 1.8bean注入的3种方式 1接口注入 2构造器注入通过constructor-arg元素完成注入 3set注入通过property元素完成注入 1.9 Spring 依赖注入四种方式 1.构造器注入 /*带参数方便利用构造器进行注入*/ public CatDaoImpl(String message){ this. message message; } bean idCatDaoImpl classcom.CatDaoImpl constructor-arg value message /constructor-arg /bean 2. setter方法 注入 通过property元素完成注入 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例如forwarduser.do?namemethod 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方法里面可以直接返回objectlist等但在方法前面要加数ResponseBody注解 2.7springMVC的post和get请求乱码问题 1post在web.xml中配置一个CharacterEncodingFilter过滤器设置为utf-8 2get修改tomcat配置文件添加编码与工程编码一致或对参数重新进行编译 2.8SpringMVC的异常处理 可以把异常抛给Spring由Spring框架处理我们只需要配置简单的异常处理器在异常处理器中添加视图页面即可 2.9SpringMVC常用的注解 1RequestMapping:用于处理请求URL映射的注解可用在类和方法上。用在类上则表示类中的所有响应请求的方法都是以该地址作为父路径 2RequestBody接受http请求的json数据将json转换为Java数据 3ResponseBody将conreoller方法返回对象转化为json对象响应给客户 2.10SpringMVC的控制器注解一般使用哪个 一般用Conntroller注解表示在表现层不能用别的注解代替 2.11拦截请求中拦截get方式提交的方法 可以在RequestMapping注解加上methodRequestMapping.get 2.12方法里得到request和session 直接在方法的形参上声明requestSpringMVC就自动把request对象传入 2.13SpringMVC的函数返回值 函数返回值有很多类型例如stringmodelAndView。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后如果执行相同的SQLmybatis不进行执行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有哪些不同 1Mybatis和hibernate不同它不完全是一个ORM框架因为MyBatis需要程序员自己编写Sql语句。 2Mybatis直接编写原生态sql可以严格控制sql执行性能灵活度高非常适合对关系数据模型要求不高的软件开发因为这类软件需求变化频繁一但需求变化要求迅速输出成果。但是灵活的前提是mybatis无法做到数据库无关性如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件工作量大。 3Hibernate对象/关系映射能力强数据库无关性好对于关系模型要求高的软件如果用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类最后部署项目 整理不易给个赞吧。。。 日后还会不断完善