java面试题(有些是转载)

1、数据库链接池的做用html

数据库链接池技术带来的优点: java

1)资源重用mysql

因为数据库链接获得重用,避免了频繁建立、释放链接引发的大量性能开销。在减小系统消耗的基础上,另外一方面也增进了系统运行环境的平稳性(减小内存碎片以及数据库临时进程线程的数量)。spring

2)更快的系统响应速度sql

数据库链接池在初始化过程当中,每每已经建立了若干数据库链接置于池中备用。此时链接的初始化工做均已完成。对于业务请求处理而言,直接利用现有可用链接,避免了数据库链接初始化和释放过程的时间开销,从而缩减了系统总体响应时间。数据库

3)新的资源分配手段 数组

对于多应用共享同一数据库的系统而言,可在应用层经过数据库链接的配置,实现数据库链接池技术,几年钱也许仍是个新鲜话题,对于目前的业务系统而言,若是设计中尚未考虑到链接池的应用,那么…….快在设计文档中加上这部分的内容吧。某一应用最大可用数据浏览器

库链接数的限制,避免某一应用独占全部数据库资源。缓存

4)统一的链接管理,避免数据库链接泄漏 安全

在较为完备的数据库链接池实现中,可根据预先的链接占用超时设定,强制收回被占用链接。从而避免了常规数据库链接操做中可能出现的资源泄漏。

 

2、java中有没有内存泄漏?

首先,什么叫内存泄露?就是一个对象已经再也不使用,但却仍然占据着内存得不到释放。虽然JVM得到的物理内存有限,但大量的内存泄露会致使Java项目运行时效率降低,还有可能抛出OutOfMemory异常。

举个例子:

Vector v = new Vector( 10 ); for ( int i = 1 ;i < 10 ; i ++ ){ Object o = new Object(); v.add(o); o = null ; } 

在这个例子里面,Vector里面装了一些对象,当o=null时,对象o已经再也不使用,原来o所在内存区域已经没法取得,但因为v中有o的引用,即便o再也不引用那块地址,系统的GC机制也不会释放掉o所在的内存,这就发生了内存泄露。 
固然,DTS中物理链接(文件、数据库、网络)未显式关闭,也会形成内存泄露。

 

3、String,StringBuffer,StringBuilder的区别

(1)都是final的,不能被继承。 
(2)String长度不可变,另外两个长度是可变的(例如StringBuffer有append方法) 
(3)StringBuffer是线程同步的,里面的每个API都添加了synchronized修饰,而StringBuilder不是线程同步的,所以拥有更好的性能。

 

4、String有重写Object的hashCode()和toString()方法吗?若是重写equals不重写hashcode会怎么样? 
有。Object.java的hashCode是native方法,应该是调用了C++的代码。

/** * Returns a hash code for this string. The hash code for a * {@code String} object is computed as * <blockquote><pre> * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] * </pre></blockquote> * using {@code int} arithmetic, where {@code s[i]} is the * <i>i</i>th character of the string, {@code n} is the length of * the string, and {@code ^} indicates exponentiation. * (The hash value of the empty string is zero.) * * @return a hash code value for this object. */ public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }

toString()方法返回的是该对象自己。 
重写equals不重写hashCode会怎样? 
仍是看HashMap.java的代码片断:

while ((e = e.next) != null) { if (e.hash == h && ((ek = e.key) == key || (ek != null && key.equals(ek)))) return e.val; }

因此底层判断的原则是先看hashcode是否是相等,再看equals是否是相等。若是重写equals不重写hashcode,就有可能出现两个对象的hashCode不相等,但equals相等,这时HashMap就get不出对应的value,虽然用户重写equals,用本身的逻辑已经断定是“同一对象”。 
(若是你认为这两个对象不相同,那么你重写equals令其相同作什么?)

 

5、Java的序列化 
(1)什么是Java的序列化?有什么用? 
将一个对象转换成与平台无关的二进制流储存在外存储器中,或在网络中传输。其余程序一旦得到这个二进制流(从文件、从数据库、从网络等)就能够将其转化为Java对象进行操做。 
举例:Java的远程方法调用(RMI)就是序列化的具体应用。RMI可让一个JVM上的对象调用其余JVM上对象的方法。RMI是J2EE的基础。 
也能够将一个JavaBean序列化后存储在数据库中。 
(2)怎么实现Java的序列化和反序列化: 
让一个类实现Serializable接口:

public class Student implements Serializable{ private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } public Student(int id) { this.id = id; } }

而后使用ObjectOutputStream流写入这个类:

public static void main(String[] args) { try { ObjectOutputStream s = new ObjectOutputStream(new FileOutputStream("E:\\1.txt")); Student s1 = new Student(1); s.writeObject(s1); s.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }

运行程序,发现生成了E:\1.txt文件,其中存储的就是s1对象。

接下来反序列化:

public static void main(String[] args) { try { ObjectInputStream s = new ObjectInputStream(new FileInputStream("E:\\1.txt")); Student s1 = (Student)s.readObject(); System.out.println(s1.getId()); s.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } }

运行程序,发现s1的学号1已经被读出。 
自定义序列化:在特殊状况下,咱们有时候不能按照java底层的默认机制对一个对象序列化。这时咱们须要在序列化的类中添加readObject()和writeObject()方法,按照本身的逻辑进行序列化和反序列化。若是还须要引用默认序列化方法,则分别调用defaultReadObject()和defaultWriteObject(). 
有时候咱们不能将全部属性都序列化(例如密码等敏感信息),这时须要在不想序列化的属性前面添加transient关键字。 
注意:(1)static修饰的属性不能被序列化;(2)若是被序列化对象的属性里面有对象(有点绕),要保证这个对象也是可序列化的。(3)对象的类名,属性会被序列化,而方法不会被序列化。(4)反序列化时要有序列化对象的.class文件,不然强转时会报错。 
(5)最好显示声明serialVersionUID:private static final long serialVersionUID = 7247714666080613254L; 
由于不一样JVM有可能对同一个类生成的serialVersionUID不一样,也可能该类的属性改变,这都会致使反序列化不回去,但若是人为指定了serialVersionUID,就不存在上述状况。 
常见的序列化协议:XML,JSON

 

6、Java如何实现多线程? 
这个基本上是必问的了,有3种方式:继承Thread类重写run函数,实现Runnable接口,实现Callable接口。 
三种方式有什么区别? 
继承Thread类,重写run方法,并new这个类调用start方法。(由于java没有多继承,因此这种方式用的不多) 
实现Runnable接口,也重写run方法,并使用new Thread(MyThread).start()执行线程。 
实现Callable接口和Runnable差很少,实现的是call方法,但能够有返回值。 

 

7、 线程安全

什么是线程安全?若是一个类在多线程访问的状况下,其行为永远与预期一致,就称为线程安全。 
反例:若是一个ArrayList类的addItem方法以下实现:

public void addItem(int item) { items[Size]=item; Size++; }

那么假设有两个线程1和2并发调用这个方法,假设此时数组为空,Size=0。 
线程1执行到items[Size]=item;的时候系统调度到线程2工做,线程1暂停,那么线程2也执行items[Size]=item;语句,那么就会覆盖掉线程1加入的那个数据(由于此时Size都是0),而执行后,Size变成2,数组中却只有1个元素,这就形成了混乱。 
如何保证线程安全? 
能够对变量使用volatile修饰;也能够对程序段或方法加synchronized修饰。 
非线程安全的类(如ArrayList、HashMap等),不能在多线程中共享,但能够在多线程环境中做为某个线程独享的属性。 

 

8、多线程环境中如何进行信息交互?Object类中的wait(),notify(),notifyAll()方法都是干什么用的? 
关于这三个方法,JavaAPI是这么解释的(节选自Object.java):

/** * Causes the current thread to wait until another thread invokes the * {@link java.lang.Object#notify()} method or the * {@link java.lang.Object#notifyAll()} method for this object. * In other words, this method behaves exactly as if it simply * performs the call {@code wait(0)}. * <p> * The current thread must own this object's monitor. The thread * releases ownership of this monitor and waits until another thread * notifies threads waiting on this object's monitor to wake up * either through a call to the {@code notify} method or the * {@code notifyAll} method. The thread then waits until it can * re-obtain ownership of the monitor and resumes execution. */ public final void wait() throws InterruptedException { wait(0); } /** * Wakes up a single thread that is waiting on this object's * monitor. If any threads are waiting on this object, one of them * is chosen to be awakened. The choice is arbitrary and occurs at * the discretion of the implementation. A thread waits on an object's * monitor by calling one of the {@code wait} methods. * <p> * The awakened thread will not be able to proceed until the current * thread relinquishes the lock on this object. The awakened thread will * compete in the usual manner with any other threads that might be * actively competing to synchronize on this object; for example, the * awakened thread enjoys no reliable privilege or disadvantage in being * the next thread to lock this object. * @throws IllegalMonitorStateException if the current thread is not * the owner of this object's monitor. * @see java.lang.Object#notifyAll() * @see java.lang.Object#wait() */ public final native void notify(); /** * Wakes up all threads that are waiting on this object's monitor. A * thread waits on an object's monitor by calling one of the * {@code wait} methods. * <p> * The awakened threads will not be able to proceed until the current * thread relinquishes the lock on this object. The awakened threads * will compete in the usual manner with any other threads that might * be actively competing to synchronize on this object; for example, * the awakened threads enjoy no reliable privilege or disadvantage in * being the next thread to lock this object. * <p> * This method should only be called by a thread that is the owner * of this object's monitor. See the {@code notify} method for a * description of the ways in which a thread can become the owner of * a monitor. */ public final native void notifyAll();

这堆E文翻译过来大概就是说,wait()方法使得持有该对象的锁的线程阻塞掉,而notify()则是唤醒一个等待该对象的线程,notifyAll()是唤醒全部等待该对象的线程。 
调用wait()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)。 
这里要注意一点:notify()和notifyAll()方法只是唤醒等待该对象的monitor的线程,并不决定哪一个线程可以获取到monitor。而若是有多个线程等待该对象,则notify()方法唤醒的具体是哪个则由JVM底层的进程调度决定。 

 

9、 多线程共用一个变量需注意什么? 
若是咱们实例化了一个实现Runnable接口的类的对象表明一个线程,这个类中定义了全局变量且run方法会修改变量时,若是有多个线程同时修改这个变量,就会出现异常状况。(由于全局信息被并行的修改会形成错误。) 
而ThreadLocal解决了这个问题。ThreadLocal类能够封装一个对象进去,被ThreadLocal封装的对象对每一个线程来讲是独享的,也就是说即便 被ThreadLocal封装的对象是全局的,它也会保证在各个线程间独立。 
接下来咱们简单的研究一下ThreadLocal.java的源码。 
ThreadLocal提供了三个API,get(),set(),remove()。分别用于取出线程本地变量、设置、清空。 
ThreadLocal底层维护了一个ThreadLocalMap,它是Thread类的一个属性。因此每一个ThreadLocalMap均与当前线程一一对应,再里面则是一个Entry[]数组,数组下标为当前线程的Hash值,对应的Entry对象里面封装了Object value。

public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }

因此get方法的具体实现逻辑是,先得到当前线程,再把当前的ThreadLocal对象自己(其中包含被封装对象在每一个线程中的版本)传进去,若是当前线程的Hash值命中,且对应下标中存有Entry对象,则返回这个对象,再取出封装在里面的value,强制转换并返回。 
set方法的实现细节是:

public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }

这个跟get差很少,若是当前线程中有ThreadLocalMap,则把value放进对应的下标中去。固然若是这个下标有可能在数组中不存在或者出现重复,这就要rehash了,在这里不作讨论。 
ThreadLocalMap的set实现细节以下:

private void set(ThreadLocal<?> key, Object value) { // We don't use a fast path as with get() because it is at // least as common to use set() to create new entries as // it is to replace existing ones, in which case, a fast // path would fail more often than not. Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { ThreadLocal<?> k = e.get(); if (k == key) { e.value = value; return; } if (k == null) { replaceStaleEntry(key, value, i); return; } } tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }

接下来是remove方法:

public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }

哈哈,写remove的时候好像做者都变懒了,把get和set里面的前两行压缩到了一行。最后调用了map的remove方法,再看看map的remove方法怎么实现的:

private void remove(ThreadLocal<?> key) { Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { if (e.get() == key) { e.clear(); expungeStaleEntry(i); return; } } }

挺简单的,就是Hash命中了之后取消对封装的那个value的引用,而后rehash一次。

接下来还有一个volatile关键字要介绍。用volatile修饰的变量,线程在每次使用变量的时候,都会去内存中读取一下该变量最后的值。这样不一样的线程访问同一变量,每次都看到的是最后的值。

 

10、 mysql索引类型,表类型

普通索引 惟一索引 主键索引 组合索引

MySQL为咱们提供了不少表类型供选择,有MyISAM、ISAM、HEAP、BerkeleyDB、InnoDB,MERGE表类型,萝卜白菜各有所爱是不假,但是真正选择何种表类型仍是要看业务须要啊,每一种表类型都有其本身的属性和优势。

目前MyISAM与InnoDB是最经常使用的,http://www.youdiancms.com/info/348.html

MyISAM存储引擎
       MyISAM是 默认存储引擎。它基于更老的ISAM代码,但有不少有用的扩展。MyISAM存储引擎的一些特征:
      全部数据值先存储低字节。这使得数据机和操做系统分离。二进制轻便性的惟一要求是机器使用补码(如最近20年的机器有的同样)和IEEE浮点格式(在主流机器中也彻底是主导的)。惟一不支持二进制兼容性的机器是嵌入式系统。这些系统有时使用特殊的处理器。
        先存储数据低字节并不严重地影响速度;数据行中的字节通常是未联合的,从一个方向读未联合的字节并不比从反向读更占用更多的资源。服务器上的获取列值的代码与其它代码相比并不显得时间紧。

         大文件(达63位文件长度)在支持大文件的文件系统和操做系统上被支持。
         当把删除和更新及插入混合的时候,动态尺寸的行更少碎片。这要经过合并相邻被删除的块,以及若下一个块被删除,就扩展到下一块来自动完成。
         每一个MyISAM表最大索引数是64。 这能够经过从新编译来改变。每一个索引最大的列数是16个。
         最大的键长度是1000字节。这也能够经过编译来改变。对于键长度超过250字节的状况,一个超过1024字节的的键块被用上。
         BLOB和TEXT列能够被索引。
        NULL值被容许在索引的列中。这个占每一个键的0-1个字节。
         全部数字键值以高字节为先被存储以容许一个更高地索引压缩。
        当记录以排好序的顺序插入(就像你使用一个AUTO_INCREMENT列之时),索引树被劈开以便高节点仅包含一个键。这改善了索引树的空间利用率。
         每表一个AUTO_INCREMEN列的内部处理。MyISAM为INSERT和UPDATE操做自动更新这一 列。这使得AUTO_INCREMENT列更快(至少10%)。在序列顶的值被删除以后就不能再利用。(当AUTO_INCREMENT列被定义为多列索 引的最后一列,能够出现重使用从序列顶部删除的值的状况 )。AUTO_INCREMENT值可用ALTER TABLE或myisamch来重置。
         若是数据文件中间的表没有自由块了,在其它线程从表读的同时,你能够INSERT新行到表中。(这被认识为并发操做 )。自由块的出现是做为删除行的结果,或者是用比当前内容多的数据对动态长度行更新的结果。当全部自由块被用完(填满),将来的插入又变成并发。
         你能够把数据文件和索引文件放在不一样目录,用DATA DIRECTORY和INDEX DIRECTORY选项CREATE TABLE以得到更高的速度,请参阅13.1.5节,“CREATE TABLE语法”。
         每一个字符列能够又不一样的字符集。
        在MyISAM索引文件里又一个标志,它代表表是否被正确关闭。若是用--myisam-recover选项启动mysqld,MyISAM表在打开得时候被自动检查,若是被表被不恰当地关闭,就修复表。
        若是你用--update-state选项运行myisamchk,它标注表为已检查。myisamchk --fast只检查那些没有这个标志的表。
        myisamchk --analyze为部分键存储统计信息,也为整个键存储统计信息。
        myisampack能够打包BLOB和VARCHAR列。

MyISAM也支持下列特征:

         支持true VARCHAR类型;VARCHAR列以存储在2个字节中的长度来开始。
         有VARCHAR的表能够有固定或动态记录长度。
         VARCHAR和CHAR列能够多达64KB。
         一个被搞乱的已计算索引对可对UNIQUE来使用。这容许你在表内任何列的合并上有UNIQUE。(尽管如此,你不能在一个UNIQUE已计算索引上搜索)。

InnoDB存储引擎
InnoDB给MySQL提供 了具备提交,回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎。InnoDB锁定在行级而且也在SELECT语句提供一个Oracle风格一致的非 锁定读。这些特点增长 了多用户部署和性能。没有在InnoDB中扩大锁定的须要,由于在InnoDB中行级锁定适合很是小的空间。InnoDB也支持FOREIGN KEY强制。在SQL查询中,你能够自由地将InnoDB类型的表与其它MySQL的表的类型混合起来,甚至在同一个查询中也能够混合。
InnoDB是为处理巨大数据量时的最大性能设计。它的CPU效率多是任何其它基于磁盘的关系数据库引擎所不能匹敌的。

InnoDB存储引擎被彻底与MySQL服务器整合,InnoDB存储引擎为在主内存中缓存数据和索引而维持它本身的缓冲池。 InnoDB存储它的表&索引在一个表空间中,表空间能够包含数个文件(或原始磁盘分区)。这与MyISAM表不一样,好比在MyISAM表中每一个表被存在 分离的文件中。InnoDB 表能够是任何尺寸,即便在文件尺寸被限制为2GB的操做系统上。

InnoDB默认地被包含在MySQL二进制分发中。Windows Essentials installer使InnoDB成为Windows上MySQL的 默认表。

InnoDB被用来在众多须要高性能的大型数据库站点上产生。著名的Internet新闻站点Slashdot.org运行在 InnoDB上。Mytrix, Inc.在InnoDB上存储超过1TB的数据,还有一些其它站点在InnoDB上处理平均每秒800次插入/更新的负荷。

InnoDB和MyISAM的区别
区别概述:
MyISAM 是MySQL中默认的存储引擎,通常来讲不是有太多人关心这个东西。决定使用什么样的存储引擎是一个很tricky的事情,可是仍是值咱们去研究一下,这里的文章只考虑 MyISAM 和InnoDB这两个,由于这两个是最多见的。

下面先让咱们回答一些问题:
你的数据库有外键吗?
你须要事务支持吗?
你须要全文索引吗?
你常用什么样的查询模式?
你的数据有多大?


思考上面这些问题可让你找到合适的方向,但那并非绝对的。若是你须要事务处理或是外键,那么InnoDB 多是比较好的方式。若是你须要全文索引,那么一般来讲 MyISAM是好的选择,由于这是系统内建的,然而,咱们其实并不会常常地去测试两百万行记录。因此,就算是慢一点,咱们能够经过使用Sphinx从 InnoDB中得到全文索引。

数据的大小,是一个影响你选择什么样存储引擎的重要因素,大尺寸的数据集趋向于选择InnoDB方式,由于其支持事务处理和故障恢复。数据库的在小 决定了故障恢复的时间长短,InnoDB能够利用事务日志进行数据恢复,这会比较快。而MyISAM可能会须要几个小时甚至几天来干这些事,InnoDB 只须要几分钟。

您操做数据库表的习惯可能也会是一个对性能影响很大的因素。好比: COUNT() 在 MyISAM 表中会很是快,而在InnoDB 表下可能会很痛苦。而主键查询则在InnoDB下会至关至关的快,但须要当心的是若是咱们的主键太长了也会致使性能问题。大批的inserts 语句在MyISAM下会快一些,可是updates 在InnoDB 下会更快一些——尤为在并发量大的时候。

因此,到底你检使用哪个呢?根据经验来看,若是是一些小型的应用或项目,那么MyISAM 也许会更适合。固然,在大型的环境下使用MyISAM 也会有很大成功的时候,但却不老是这样的。若是你正在计划使用一个超大数据量的项目,并且须要事务处理或外键支持,那么你真的应该直接使用InnoDB方 式。但须要记住InnoDB 的表须要更多的内存和存储,转换100GB 的MyISAM 表到InnoDB 表可能会让你有很是坏的体验。

区别总结:
1.InnoDB不支持FULLTEXT类型的索引。
2.InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行,可是MyISAM只要简单的读出保存好的行数便可。注意的是,当count(*)语句包含 where条件时,两种表的操做是同样的。
3.对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,可是在MyISAM表中,能够和其余字段一块儿创建联合索引。
4.DELETE FROM table时,InnoDB不会从新创建表,而是一行一行的删除。
5.LOAD TABLE FROM MASTER操做对InnoDB是不起做用的,解决方法是首先把InnoDB表改为MyISAM表,导入数据后再改为InnoDB表,可是对于使用的额外的InnoDB特性(例如外键)的表不适用。

另外,InnoDB表的行锁也不是绝对的,若是在执行一个SQL语句时MySQL不能肯定要扫描的范围,InnoDB表一样会锁全表,例如update table set num=1 where name like “%aaa%”


提高InnoDB性能的方法:
MyISAM和InnoDB存储引擎性能差异并非很大,针对InnoDB来讲,影响性能的主要是 innodb_flush_log_at_trx_commit 这个选项,若是设置为1的话,那么每次插入数据的时候都会自动提交,致使性能急剧降低,应该是跟刷新日志有关系,设置为0效率可以看到明显提高,固然,同 样你能够SQL中提交“SET AUTOCOMMIT = 0”来设置达到好的性能。另外,还据说经过设置innodb_buffer_pool_size可以提高InnoDB的性能,可是我测试发现没有特别明显 的提高。

基本上咱们能够考虑使用InnoDB来替代咱们的MyISAM引擎了,由于InnoDB自身不少良好的特色,好比事务支持、存储 过程、视图、行级锁定等等,在并发不少的状况下,相信InnoDB的表现确定要比MyISAM强不少,固然,相应的在my.cnf中的配置也是比较关键 的,良好的配置,可以有效的加速你的应用。
任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优点。

 

 11、http请求的过程

HTTP通讯机制是在一次完整的HTTP通讯过程当中,Web浏览器与Web服务器之间将完成下列7个步骤:

1. 创建TCP链接
在HTTP工做开始以前,Web浏览器首先要经过网络与Web服务器创建链接,该链接是经过TCP来完成的,该协议与IP协议共同构建Internet,即著名的TCP/IP协议族,所以Internet又被称做是TCP/IP网络。HTTP是比TCP更高层次的应用层协议,根据规则,只有低层协议创建以后才能进行更高层协议的链接,所以,首先要创建TCP链接,通常TCP链接的端口号是80。

2. Web浏览器向Web服务器发送请求命令 
一旦创建了TCP链接,Web浏览器就会向Web服务器发送请求命令。例如:GET/sample/hello.jsp HTTP/1.1。

3. Web浏览器发送请求头信息 
浏览器发送其请求命令以后,还要以头信息的形式向Web服务器发送一些别的信息,以后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。

4. Web服务器应答 
客户机向服务器发出请求后,服务器会客户机回送应答, HTTP/1.1 200 OK ,应答的第一部分是协议的版本号和应答状态码。

5. Web服务器发送应答头信息 
正如客户端会随同请求发送关于自身的信息同样,服务器也会随同应答向用户发送关于它本身的数据及被请求的文档。

6. Web服务器向浏览器发送数据 
Web服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据。

7. Web服务器关闭TCP链接 
通常状况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP链接,而后若是浏览器或者服务器在其头信息加入了这行代码:Connection:keep-alive

TCP链接在发送后将仍然保持打开状态,因而,浏览器能够继续经过相同的链接发送请求。保持链接节省了为每一个请求创建新链接所需的时间,还节约了网络带宽。

 

TCP创建链接的过程是三次握手

在TCP/IP协议中,TCP协议提供可靠的链接服务,采用三次握手创建一个链接。 
第一次握手:创建链接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认; 

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时本身也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。 完成三次握手,客户端与服务器开始传送数据. 

 

 

 12、Hibernate数据对象的状态

Hibernate中的对象有3种状态:Transient(瞬时),Persistent(持久)和Detached(托管)。

1 瞬时状态: 

      由new命令开辟内存空间的java对象,例如Student stu = new Student();若是没有变量对他引用,它将被JVM回收。瞬时对象在内存中孤立存在,他的意义仅是携带信息的载体,不和数据库中的数据有任何的关联。经过session的save()和saveOrUpdate()方法能够把一个瞬时对象与数据库相关联,并把瞬时对象携带的信息经过配置文件所作的映射插入到数据库中,这个瞬时对象就成了持久化对象,拥有和数据库记录相同的id标示(Hibernate自动将id赋予它) 

     瞬时对象的特色是:

    (1)不和Session实例关联

    (2)在数据库中没有和瞬时对象关联的记录

2 持久化状态:

      持久的实例在数据库中有对应的记录,拥有一个持久化标识。持久对象老是与Session和Transaction相关联,在一个Session中,对持久对象的改变不会立刻对数据库进行变动,而必须在Transaction终止,也就是执行commit()以后,才在数据库中真正运行SQL进行变动,持久对象的状态才会与数据库进行同步。在同步以前的持久对象成为脏(dirty)对象。

     使用find(),get(),load()和iterater()等方法查询到得数据对象,都是持久化对象;若是一个瞬时对象被持久对象引用,则该对象也会自动变为持久对象。

     若是使用delete()方法,它就会变为瞬时对象;当一个Session执行close()或clear()、evict()以后,持久对象就会变为托管对象。

    持久对象的特色:

    (1)和Session实例关联

    (2)在数据库中有和持久对象关联的记录

3 托管状态:

      与持久对象关联的Session被关闭后,对象就变为托管的。对托管对象的引用依然有效,对象可继续被修改。托管对象若是从新关联到某个新的Session上,会再次转变为持久的。托管状态期间的改动将会被持久化到数据库。

     托管状态拥有数据库标识id,因此它能够经过update()、saveOrUpdate()和lock()等方法,再度与持久层关联。

     托管对象的特色:

     (1)本质上和瞬时对象相同

     (2)只是比瞬时对象多了一个数据库记录标识值id

 

 十3、内存排序和数据库排序分页的优缺点

 我的理解,

内存排序能够将数据一会儿全取出来,放入内存中进行排序,可是占用内存。

数据库排序,每次换页都要从数据库中从新提取数据,可是不占用太多内存。

 

十4、transient

Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,咱们不想用 serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,能够在这个域前加上关键字transient。 当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。

 

十5、spring ioc容器配置元数据的方式

http://blog.csdn.net/helloboat/article/details/51199319

基于XML文件进行配置。

基于注解进行配置。 @service @repository @controller 自动扫描

基于Java程序进行配置(Spring 3+)

用@component标注Car Person

  1. package com.lovo.config;    
  2.     
  3. import org.springframework.context.annotation.Bean;    
  4. import org.springframework.context.annotation.Configuration;    
  5.     
  6. import com.lovo.bean.Car;    
  7. import com.lovo.bean.Person;    
  8.     
  9. @Configuration    
  10. public class AppConfig {    
  11.     
  12.     @Bean    
  13.     public Car car() {    
  14.         return new Car("Benz", 320);    
  15.     }    
  16.         
  17.     @Bean    
  18.     public Person person() {    
  19.         return new Person("骆昊", 34);    
  20.     }    

 

  1. package com.lovo.config;    
  2.     
  3. import org.springframework.context.annotation.Bean;    
  4. import org.springframework.context.annotation.Configuration;    
  5.     
  6. import com.lovo.bean.Car;    
  7. import com.lovo.bean.Person;    
  8.     
  9. @Configuration    
  10. public class AppConfig {    
  11.     
  12.     @Bean    
  13.     public Car car() {    
  14.         return new Car("Benz", 320);    
  15.     }    
  16.         
  17.     @Bean    
  18.     public Person person() {    
  19.         return new Person("骆昊", 34);    
  20.     }    
相关文章
相关标签/搜索