笔试题:
静态变量和实例变量的区别
在语法定义上的区别:静态变量前要加 static 关键字,而实例变量前则不加。
在程序运行时的区别:
实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。
静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。
总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直
接使用类名来引用。
写 clone()方法时,通常都有一行代码,是什么?
clone 有缺省行为,super.clone();因为首先要把父类中的成员复制到位,
然后才是复制自己的成员。
java 中实现多态的机制是什么?
靠的是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
abstract 的method是否可同时是 static,是否可同时是native,是否可同时是synchronized?
abstract 的 method不可以是 static的,因为抽象的方法是要被子类实现的,而 static与子类扯不上关系!native方法表示该方法要用另外一种依赖平台的编程语言实现的,不存在着被子类实现的问题,所以,它也不能是抽象的,不能与abstract 混用。
什么是内部类?Static Nested Class和 Inner Class的不同。
Inner Class(内部类)定义在类中的类。
内部类中不能定义静态成员,内部类通常是用于创建内部对象用的,内部类可以直接访问外部类中的成员变量,内部类可以定义在外部类的方法外面,也可以定义在外部类的方法体中。
在方法外部定义的内部类前面可以加上 static 关键字,从而成为Static Nested Class,它不再具有内部类的特性。Static Nested Class 与普通类在运行时的行为和功能上没有什么区别,只是在编程引用时的语法上有一些差别,它可以定义成 public、protected、默认的、private 等多种类型,而普通类只能定义成 public 和默认的这两种类型。在外面引用 Static Nested Class 类的名称为“外部类名.内部类名”。在外面不需要创建外部类的实例对象,就可以直接创建 Static Nested Class。
内部类可以引用它的包含类的成员吗?有没有什么限制?
完全可以。
如果不是静态内部类,那没有什么限制!如果你把静态嵌套类当作内部类的一种特例,那在这种情况下不可以访问外部类的普通成员变量,而只能访问外部类中的静态成员。
HashMap 和 Hashtable 的区别
就 HashMap 与 HashTable 主要从三方面来说。
一.历史原因:Hashtable 是基于陈旧的 Dictionary 类的,HashMap 是 Java
1.2 引进的 Map 接口的一个实现;
二.同步性:Hashtable 是线程安全的,也就是说是同步的,而 HashMap 是线
程序不安全的,不是同步的;
三. 值:只有 HashMap 可以让你将空值作为一个表的条目的 key 或 Value。
List、Map、Set 三个接口,存取元素时,各有什么特点?
List与Set都是单列元素的集合,它们有一个功共同的父接口Collection。
Set里面不允许有重复的元素,
存元素:add方法有一个boolean的返回值,当集合中没有某个元素,此时add方法可成功加入该元素时,则返回true;当集合含有与某个元素equals相等的元素时,此时add方法无法加入该元素,返回结果为false。
取元素:没法说取第几个,只能以Iterator接口取得所有的元素,再逐一遍历各个元素。
List表示有先后顺序的集合,
存元素:多次调用add(Object)方法时,每次加入的对象按先来后到的顺序排序,也可以插队,即调用add(int index,Object)方法,就可以指定当前对象在集合中的存放位置。
取元素:方法1:Iterator接口取得所有,逐一遍历各个元素
方法2:调用get(index i)来明确说明取第几个。
Map是双列的集合,存放用put方法:put(obj key,obj value),每次存储时,要存储一对key/value,不能存储重复的key,这个重复的规则也是按equals比较相等。
取元素:用get(Object key)方法根据key获得相应的value。
也可以获得所有的key的集合,还可以获得所有的value的集合,
还可以获得key和value组合成的Map.Entry对象的集合。
说出 ArrayList,Vector, LinkedList 的存储性能和特性
ArrayList 和 Vector 都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector 由于使用了 synchronized 方法(线程安全),通常性能上较 ArrayList 差。
LinkedList 使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。LinkedList也是线程不安全的,LinkedList 提供了一些方法,使得 LinkedList 可以被当作堆栈和队列来使用。
你所知道的集合类都有哪些?主要方法?
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set-TreeSet-HashSet-LinkedHashSet
Map
├Hashtable
├HashMap
└WeakHashMap
Collection接口
Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements)。一些Collection允许相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的“子接口”如List和Set。
所有实现Collection接口的类都必须提供两个标准的构造函数:无参数的构造函数用于创建一个空的Collection,有一个Collection参数的构造函数用于创建一个新的Collection,这个新的Collection与传入的Collection有相同的元素。后一个构造函数允许用户复制一个Collection。
如何遍历Collection中的每一个元素?不论Collection的实际类型如何,它都支持一个iterator()的方法,该方法返回一个迭代子,使用该迭代子即可逐一访问Collection中每一个元素。典型的用法如下:
Iterator it = collection.iterator(); // 获得一个迭代子
while(it.hasNext()) {
Object obj = it.next(); // 得到下一个元素
}
由Collection接口派生的两个接口是List和Set。
List接口
List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。
和下面要提到的Set不同,List允许有相同的元素。
除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。
实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。
LinkedList类
LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。
注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:
List list = Collections.synchronizedList(new LinkedList(...));
ArrayList类
ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList没有同步。
size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。
每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。
和LinkedList一样,ArrayList也是非同步的(unsynchronized)。
Vector类
Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和ArrayList创建的Iterator是同一接口,但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例如,添加或删除了一些元素),这时调用Iterator的方法时将抛出ConcurrentModificationException,因此必须捕获该异常。
Stack 类
Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。
Set接口
Set是一种不包含重复的元素的Collection,即任意的两个元素e1和e2都有e1.equals(e2)=false,Set最多有一个null元素。
很明显,Set的构造函数有一个约束条件,传入的Collection参数不能包含重复的元素。
请注意:必须小心操作可变对象(Mutable Object)。如果一个Set中的可变元素改变了自身状态导致Object.equals(Object)=true将导致一些问题。
Map接口
请注意,Map没有继承Collection接口,Map提供key到value的映射。一个Map中不能包含相同的key,每个key只能映射一个value。Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射。
Hashtable类
Hashtable继承Map接口,实现一个key-value映射的哈希表。任何非空(non-null)的对象都可作为key或者value。
添加数据使用put(key, value),取出数据使用get(key),这两个基本操作的时间开销为常数。
Hashtable通过initial capacity和load factor两个参数调整性能。通常缺省的load factor 0.75较好地实现了时间和空间的均衡。增大load factor可以节省空间但相应的查找时间将增大,这会影响像get和put这样的操作。
使用Hashtable的简单示例如下,将1,2,3放到Hashtable中,他们的key分别是”one”,”two”,”three”:
Hashtable numbers = new Hashtable();
numbers.put(“one”, new Integer(1));
numbers.put(“two”, new Integer(2));
numbers.put(“three”, new Integer(3));
要取出一个数,比如2,用相应的key:
Integer n = (Integer)numbers.get(“two”);
System.out.println(“two = ” + n);
由于作为key的对象将通过计算其散列函数来确定与之对应的value的位置,因此任何作为key的对象都必须实现hashCode和equals方法。hashCode和equals方法继承自根类Object,如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个对象相同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一定不同,如果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希表的操作。
如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的get方法返回null),要避免这种问题,只需要牢记一条:要同时复写equals方法和hashCode方法,而不要只写其中一个。
Hashtable是同步的。
HashMap类
HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key。,但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。
WeakHashMap类
WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。
总结
如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。
如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。
要特别注意对哈希表的操作,作为key的对象要正确复写equals和hashCode方法。
尽量返回接口而非实际的类型,如返回List而非ArrayList,这样如果以后需要将ArrayList换成LinkedList时,客户端代码不用改变。这就是针对抽象编程。
字节流与字符流的区别
流: 所有流的顶层父类都是抽流,因此不能被实例化
Java中任何的输入与输出都是以流的形式进行的。
1、输入与输出的形式:输入流、输出流
以自己的程序为参照:输入流 >> 自己的程序 << 输出流
2、数据 分为 字节和字符;以数据可以 分为 字节流和字符流; 字符流是在字节流的基础上生成而来。
字节流:
字节输出流 ,抽象类
OutputStream 字节输出流的统一父类,以OutputStream结尾的 就一定是字节输出流
字节输入流 ,抽象类
InputStream 字节输入流的统一父类,以InputStream结尾的 就一定是字节输入流
字符流: 只能处理文本文件,处理字符如:js、xml、txt等
writer : 字符输出流的统一父类
Reader 字符输入流的统一父类
PrintStream流: 字节流,显示是字符
打印的字符都被默认转换为字节,在需要写入字符而不是字节的情况下,使用PrintWriter类。
System.out.println() : 输出流,在控制台打印,永远不会抛出IOException。
什么是 java 序列化,如何实现 java 序列化?或者请解释Serializable 接口的作用。
什么是序列化:将对象保存于一个流中,只能将支持 java.io.Serializable 接口的对象写入流中,必须实现Serializable 。
ObjectOutputStream:序列化
writeObject 方法用于将对象写入流中。所有对象(包括 String 和数组)都可以通过 writeObject 写入。
ObjectInputStream:反序列化 把流从对象中取出来
Serializable :JDk需要》= 1.1
Java原生序列化
Java原生序列化方法即通过Java原生流(InputStream和OutputStream之间的转化)的方式进行转化。需要注意的是JavaBean实体类必须实现Serializable接口,否则无法序列化。
Json序列化
Json序列化一般会使用jackson包,通过ObjectMapper类来进行一些操作,比如将对象转化为byte数组或者将json串转化为对象。现在的大多数公司都将json作为服务器端返回的数据格式。
FastJson序列化
fastjson 是由阿里巴巴开发的一个性能很好的Java 语言实现的 Json解析器和生成器。特点:速度快,测试表明fastjson具有极快的性能,超越任其他的java json parser。功能强大,完全支持java bean、集合、Map、日期、Enum,支持范型和自省。无依赖,能够直接运行在Java SE 5.0以上版本。支持Android。使用时候需引入FastJson第三方jar包。
ProtoBuff序列化
ProtocolBuffer是一种轻便高效的结构化数据存储格式,可以用于结构化数据序列化。适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
一个对象有对应的一些属性,把这个对象保存在硬盘上的过程叫做”持久化”。
对象的默认序列化机制写入的内容是:对象的类,类签名,以及非瞬态和非静态字段的值。
序列化能把堆内存中的对象的生命周期延长,做持久化操作.当下次再需要这个对象的时候,我们不用new了,直接从硬盘中读取就可以了。把对象存储到硬盘上的一个文件中,这个文件的标准扩展名是(.object)。
描述一下 JVM 加载 class 文件的原理机制?
JVM 中类的装载是由 ClassLoader 和它的子类来实现的,Java ClassLoader 是一个重要的 Java 运行时系统组件。它负责在运行时查找和装入类文件的类。
heap 和 stack 有什么区别。
java 的内存分为两类,一类是栈内存,一类是堆内存。
栈内存是指程序进入一个方法时,会为这个方法单独分配一块私属存储空间,用于存储这个方法内
部的局部变量,当这个方法结束时,分配给这个方法的栈会释放,这个栈中的变量也将随之释放。
堆是与栈作用不同的内存,一般用于存放不放在当前方法栈中的那些数据,例如,使用 new 创建的对象都放在堆里,所以,它不会随方法的结束而消失。方法中的局部变量使用 final 修饰后,放在堆中,而不是栈中。
GC 是什么? 为什么要有 GC?
GC 是垃圾收集的意思。
内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java 提供的 GC 功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java 语言没有提供释放已分配内存的显示操作方法。
垃圾回收的优点和原理。并考虑 2 种回收机制。
Java 语言中一个显著的特点就是引入了垃圾回收机制,使内存管理的问题迎刃而解,它使得 Java 程序员在编写程序的时候不再需要考虑内存管理。
垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清楚和回收,
程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。
回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。
典型的垃圾收集算法
第一种:标记-清除法
直接在内存里标记无用的对象,然后直接回收。
第二种:复制算法:
将内存划分为大小相等的两块,当一块的内存用完了,就讲还存活的对象复制到另外一块上面,然后将之前的那块清理掉。
第三种:标记-整理算法
将存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
第四种:分代收集算法:(当前商业虚拟机都采用这个哦)
根据对象的存活中期的不同将内存划分为几块,一般java堆分为新生代和老年代;
新生代:用复制算法
老年代:用标记整理算法进行回收
垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?
对于 GC 来说,当程序员创建对象时,GC 就开始监控这个对象的地址、大小以及使用情况。通常,GC 采用有向图的方式记录和管理堆(heap)中的所有对象。
可以。
程序员可以手动执行 System.gc(),通知 GC 运行,但是 Java 语言规范并不保证 GC 一定会执行。
java 中会存在内存泄漏吗,请简单描述。
所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。
java 中有垃圾回收机制,它可以保证一对象不再被引用的时候,即对象将自动被垃圾回收器从内存中清除掉。通俗地说,就是程序员可能创建了一个对象,以后一直不再使用这个对象,这个对象却一直被引用,即这个对象无用但是却无法被垃圾回收器回收的,这就是 java 中可能出现内存泄露的情况。
如果一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内部类持久外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会造成内存泄露。
能不能自己写个类,也叫 java.lang.String?
可以,但在应用的时候,需要用自己的类加载器去加载,否则,系统的类加载器永远只是去加载 jre.jar 包中的那 java.lang.String。由于在 tomcat 的web 应用程序中,都是由 webapp 自己的类加载器先自己加载 WEB-INF/classess目录中的类,然后才委托上级的类加载器加载,如果我们在 tomcat 的 web 应用程序中写一个 java.lang.String,这时候 Servlet 程序加载的就是我们自己写的 java.lang.String,但是这么干就会出很多潜在的问题,原来所有用了java.lang.String 类的都将出现问题。虽然 java 提供了 endorsed 技术,可以覆盖 jdk 中的某些类,具体做法是….。但是,能够被覆盖的类是有限制范围,反正不包括java.lang 这样的包中的类。
synchronized与Lock的区别
悲观锁和乐观锁
悲观锁, 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁, 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
Socket和WebSocket
WebSocket:
Html5的新协议,实现了浏览器与服务器的全双工通信。
原理:
和Http一样,都是应用层的协议,是一种双向通信协议,建立在TCP之上。
目的:
即时通讯,替代轮询。
在Websocket中,只需要服务器和浏览器之间通过Http协议进行一个握手动作,然后建立一条TCP的通信通道,进行数据传输。
不同点:
·1. WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息。HTTP是单向的。
·2. WebSocket是需要握手进行建立连接的。
联系:
WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协议的。
Socket:
继承于Object。套接字,两台机器间通信的端点,通常是用来实现客户方和服务方的连接。一个Socket由一个IP地址和一个端口号唯一确定。Socket编程主要是指基于TCP/IP协议的网络编码。
Socket工作过程:
1、创建Socket;
2、打开连接到Socket的输入输出流;
3、按照一定的协议对Socket进行读写操作;
4、关闭Socket。
模式:
结构模式:适配器模式、代理模式、装饰模式
行为模式:命令模式、状态模式、访问者模式、中介者模式
创建型模式:单例模式、工厂模式、抽象工厂模式、原型模式、
对ajax的理解:
ajax是一种异步通信技术,ajax技术的核心是XMLHttpRequest对象(简称XHR)。
XHR用法:
1.创建XHR对象
2.调用open()方法创建请求 // 发送的请求类型、请求的URL、是否异步发送请求
3.调用send()方法发送请求
4.onreadychange捕获请求的状态码
5.判断状态吗是否成功
6.调用ajax的responseText属性返回数据
AOP和IOC:
IOC:控制反转。
将控制权交给容器来进控制对象的创建及维护。反转:将对象的权利交给容器来进行处理。目的:获得更好的扩展性和可维护性。
IOC是通过Bean来进行控制的。
依赖注入:通过web容器,动态的将依赖对象注入到另一个对象的组件中。简单的说:就是将某些参数依赖注入到对象中。
Spring采用依赖注入方式为Bean的属性赋值。
依赖注入方式:
手动注入:
Setter、基本类型注入、Spring组件注入和集合注入。
注解注入。
使用注解配置Spring的组件有哪些??
Component、Service、Controller、Repository.
AOP:面向切面编程
AOP 的核心组件
切面(Aspect):封装通用逻辑的组件,可以作用到其它组件上。如日志切面、权限切面、事务切面等。
切入点(Pointcut):指定哪些组件 哪些方法使用切面组件。Spring使用表达式来实现该指定。
通知: 指定组件作用到目标组件的具体位置,是切面的具体实现。
前置通知:在目标组件的方法执行前执行
后置通知:在目标组件的方法执行并返回参数后执行;有返回值情况下才执行,若不配返回类型和返回值也执行;有异常时,不执行。
异常通知:在目标组件的方法抛出异常时执行
最终通知:在目标组件执行后或在异常执行通知前 执行
环绕通知:包含前4个通知,ProceedingJoinPoint参数。
连接点(Joinpoint):就是程序在运行过程中能够插入切面的地点。例如,方法调用、异常抛出或字段修改等,但spring只支持方法级的连接点。
目标对象(Target):就是那些即将切入切面的对象,也就是那些被通知的对象。
织入(Weaving):将切面应用到目标对象从而创建一个新的代理对象的过程。
spring的AOP机制:
AOP面向方面编程基于IoC,是对OOP的补充;
实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。
Spring实现AOP:JDK动态代理和CGLIB代理 JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理;其核心的两个类是InvocationHandler和Proxy。 CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强;需要引入包asm.jar和cglib.jar。使用AspectJ注入式切面和@AspectJ注解驱动的切面实际上底层也是通过动态代理实现的。
为什么要有AOP切面编程:
(1)解耦
(2)重复利用代码
(3)便于装卸
数据库的优化:
a) 选择合适的字段,比如邮箱字段可以设为char(6),尽量把字段设置为notnull,这样查询的时候数据库就不需要比较null值
b) 使用关联查询(left join on)查询代替子查询
c) 使用union联合查询手动创建临时表
d) 开启事物,当数据库执行多条语句出现错误时,事物会回滚,可以维护数据库的完整性
e) 使用外键,事物可以维护数据的完整性但是它却不能保证数据的关联性,使用外键可以保证数据的关联性
f) 使用索引,索引是提高数据库性能的常用方法,它可以令数据库服务器以比没有索引快的多的速度检索特定的行,特别是对于max,min,order by查询时,效果更明显
g) 优化的查询语句。
JavaScript:简单概述
网景公司开发基于对象事件驱动的编程语言,直接运行在Web浏览器中。可以实现很多网页动态效果。
JavaScript教程语言概况:
实现了一种实时的、动态的、可交式的表达能力。是众多脚本语言中较为优秀的一种。
脚本语言、基于对象、简单性、安全性、动态性 、跨平台性
使用场景:
嵌入动态文本于HTML页面,对浏览器事件做出响应。读写HTML元素。在数据被提交到服务器之前验证数据。检测访客的浏览器信息。控制cookies,包括创建和修改等。基于Node.js技术进行服务器端编程。
引入方式:
内嵌javascript脚本
引入外部的javascript文件
在事件中编写javascript。
前端的组成:
结构层、行为层、表现层
Html:负责一个页面的结构
Css:负责一个页面的样式
JavaScript:负责与用户进行交互
SSM基本原理
SpringMVC:
1.客户端发送请求到DispacherServlet(分发器)
2.由DispacherServlet控制器查询HanderMapping,找到处理请求的Controller
3.Controller调用业务逻辑处理后,返回ModelAndView
4.DispacherSerclet查询视图解析器,找到ModelAndView指定的视图
5.视图负责将结果显示到客户端
Mybatis:
mybatis是对jdbc的封装,它让数据库底层操作变的透明。mybatis的操作都是围绕一个sqlSessionFactory实例展开的。mybatis通过配置文件关联到各实体类的Mapper文件,Mapper文件中配置了每个类对数据库所需进行的sql语句映射。在每次与数据库交互时,通过sqlSessionFactory拿到一个sqlSession,再执行sql命令。
Spring工作原理:
Spring 已经用过一段时间了,感觉Spring是个很不错的框架。内部最核心的就是IOC了,
动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的反射
反射其实就是在运行时动态的去创建、调用对象,Spring就是在运行时,跟xml Spring的配置
文件来动态的创建对象,和调用对象里的方法的 。
Spring还有一个核心就是AOP这个就是面向切面编程,可以为某一类对象 进行监督和控制(也就是
在调用这类对象的具体方法的前后去调用你指定的 模块)从而达到对一个模块扩充的功能。这些都是通过
配置类达到的。
Spring目的:就是让对象与对象(模块与模块)之间的关系没有通过代码来关联,都是通过配置类说明
管理的(Spring根据这些配置 内部通过反射去动态的组装对象)
要记住:Spring是一个容器,凡是在容器里的对象才会有Spring所提供的这些服务和功能。
Spring事务
事物的四大特性:
atomic(原子性):要么都发生,要么都不发生。
consistent(一致性):数据应该不被破坏。
isolate(隔离性):用户间操作不相混淆
durable(持久性):永久保存,例如保存到数据库中等
声明式事务管理
spring的事务管理器: spring没有直接管理事务,只是开发了事物管理器调用第三方组件完成事物控制。
READ_COMMITTED允许在并发事务已经提交后读取。
REPEATABLE_READ 对相同字段的多次读取是一致的,除非数据被事务本身改变。
SERIALIZABLE完全服从ACID的隔离级别。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的。
隔离级别 | 脏读 | 非重复读 | 幻像读 |
read uncommitted | 允许 | 允许 | 允许 |
read committed |
| 允许 | 允许 |
repeatable read |
|
| 允许 |
serializable |
|
|
|
Spring事务的配置方式:
第一种方式:每个Bean都有一个代理
第二种方式:所有Bean共享一个代理基类
第三种方式:使用拦截器
第四种方式:使用tx标签配置的拦截器
第五种方式:全注解