1. 程式人生 > >常用JAVA面試題集合

常用JAVA面試題集合

1、簡單講一下java的跨平臺原理
    Java源程式通過編譯器(也就是Java平臺)編譯成Class檔案(位元組碼檔案),然後通過Java虛擬機器(JVM)翻譯成為對應的OS指令;可以讓不同的系統都可以去執行此檔案。

2、String和StringBuilder的區別, StringBuffer 和 StringBuilder 的區別
    1)String、StringBuffer、StringBuilder它們三個都是來表示和操作字串的
    2)String是內容不可變的字串,Stirng底層使用了一個不可變的字元陣列(final char[]);而StringBuilder和StringBuffer是內容可以改變的字串,StringBuilder和StringBuffer底層使用的是可變陣列(沒有使用final來修飾)----char value[]
    3)拼接字串的方式不同:String用cancat或者+號拼接;而StringBuffer與StringBuilder用append來進行追加
    4)StringBuilder是執行緒不安全的,效率較高,而StringBuffer是執行緒安全的,效率較低(F安D不)
    5)由以上得知:String:適用於少量的字串操作的情況;StringBuilder:適用於單執行緒下在字元緩衝區進行大量操作的情況;StringBuffer:適用多執行緒下在字元緩衝區進行大量操作的情況

3、List和Set區別?Set集合去重規則?
    List,Set都是繼承自Collection介面
    1)List集合特點:元素放入有序,元素可重複 ,可以儲存空值且可以重複空
    2)Set集合特點:元素放入無序,元素不可重複(重複元素會覆蓋掉),可以儲存空值當時不能重複
    3)如果新增物件,一般都需要實現equals和hashcode方法,Set集合去重規則
        3.1、根據equals和hashCode來判斷是否是同一個元素
        3.2、向Set集合中新增一個元素;如果equals返回false->新增成功;如果返回true->再去判斷它的hashcode是否相同;如果不相同則新增成功;否則新增失敗。

4、ArrayList和LinkedList區別
    ArrayList和LinkedList都實現了List介面
    1)ArrayList特點:是基於索引的資料介面,它的底層是陣列;所以查詢速度快
    2)LinkedList特點:是以元素列表的形式儲存它的資料,底層實現是連結串列;所以插入、刪除操作速度更快,因為當元素被新增到集合任意位置的時候,不需要像陣列那樣重新計算大小或者是更新索引。
    3)LinkedList比ArrayList更佔記憶體,因為LinkedList為每一個節點儲存了兩個引用,一個指向前一個元素,一個指向下一個元素。

5、HashMap和HashTable區別


    1)它們都屬於Map介面的類,實現了將惟一鍵對映到特定的值上。
    2)對外提供的介面不同: Hashtable比HashMap多提供了elments() 和contains() 兩個方法。
    3)對Null key 和Null value的支援不同 :HashMap 類沒有分類或者排序。它允許一個 null 鍵和多個 null 值;而Hashtable 類似於 HashMap,但是既不支援Null key也不支援Null value。
    4)執行緒安全性不同 :HashMap執行緒不安全;Hashtable執行緒安全
    5) 初始大小和每次擴充容量大小的不同 :Hashtable預設的初始大小為11,之後每次擴充,容量變為原來的2n+1。HashMap預設的初始化大小為16。之後每次擴充,容量變為原來的2倍。
    6)速度不同:因為關係到是否空值和執行緒安全性的關係;所以Hashtable速度比HashMap速度慢;所以Hashtable很少用。

6、ArrayList和Vector有何異同點
    1)Vector的方法都是同步的(Synchronized),是執行緒安全的(thread-safe),而ArrayList的方法不是,由於執行緒的同步必然要影響效能,因此,ArrayList的效能比Vector好。
    2) 當Vector或ArrayList中的元素超過它的初始大小時,Vector會將它的容量翻倍,而ArrayList只增加50%的大小,這樣,ArrayList就有利於節約記憶體空間。

7、佇列和棧是什麼,列出它們的區別
    1)規則不同
        1.1、 佇列:先進先出(First In First Out)FIFO
        1.2、棧:先進後出(First In Last Out )FILO
    2)對插入和刪除操作的限定不同
        2.1、佇列:只能在表的一端進行插入,並在表的另一端進行刪除;
        2.2、棧:只能在表的一端插入和刪除。
    3)遍歷資料速度不同
        3.1、佇列:基於地址指標進行遍歷,而且可以從頭部或者尾部進行遍歷,但不能同時遍歷,無需開闢空間,因為在遍歷的過程中不影響資料結構,所以遍歷速度要快。
        3.2、棧:只能從頂部取資料,也就是說最先進入棧底的,需要遍歷整個棧才能取出來,而且在遍歷資料的同時需要為資料開闢臨時空間,保持資料在遍歷前的一致性。

8、Iterater和ListIterator之間有什麼區別
    (1)我們可以使用Iterator來遍歷Set和List集合,而ListIterator只能遍歷List。
    (2)Iterator只可以向前遍歷,而LIstIterator可以雙向遍歷。
    (3)ListIterator從Iterator介面繼承,然後添加了一些額外的功能,比如新增一個元素、替換一個元素、獲取前面或後面元素的索引位置。

9、哪些集合類是執行緒安全的?為何Map介面不繼承Collection介面?
    1)Vector?、HashTable、ConcurrentHashMap、Statck
    2)儘管Map介面和它的實現也是集合框架的一部分,但Map不是集合,集合也不是Map。因此,Map繼承Collection毫無意義,反之亦然。如果Map繼承Collection介面,那麼元素去哪兒?Map包含key-value對,它提供抽取key或value列表集合的方法,但是它不適合“一組物件”規範。

10、遍歷一個List、Map有哪些不同的方式
    1)List泛型只有一個;而Map有兩個;是以鍵值對的形式出現的
    遍歷一個List:1、使用Iterator或者ListIterator來遍歷
             2、因為List底層是陣列;所以可以利用普通for迴圈通過List大小(List.size())來逐個遍歷。
             3、使用foreach來遍歷
    遍歷一個Map:1、同時得到key與value的值使用EntrySet方式
                2、使用KeySet,遍歷key,然後通過map.get(key)獲得對應的value
                  3、如果只需要value,可以:
            1. 使用EntrySet遍歷value,同上面的方法一
            2. 通過keySet遍歷key,然後通過map.get(key)得到value,同上面的方法二
            3. 通過Map物件“點”values直接遍歷value

11、HashSet內部實現機制?HashMap內部實現機制?
    1)對於HashSet而言,它是基於HashMap實現的,(HashSet底層使用HashMap來儲存所有元素,因此HashSet的實現比較簡單,相關HashSet的操作),基本上都是直接呼叫底層HashMap的相關方法來完成。
    2)HashMap基於hashing原理,我們通過put()和get()方法儲存和獲取物件。當我們將鍵值對傳遞給put()方法時,它呼叫鍵物件的hashCode()方法來計算hashcode,讓後找到bucket位置來儲存值物件。當獲取物件時,通過鍵物件的equals()方法找到正確的鍵值對,然後返回值物件。

12、集合排序方式(不同的集合型別排序方式)
    1)第一種稱為自然排序,參與排序的物件需實現comparable介面,重寫其compareTo()方法,方法體中實現物件的比較大小規則.
    2)第二種叫定製排序,或自定義排序,需編寫匿名內部類,先new一個Comparator介面的比較器物件c,同時實現compare()其方法;?

13、多執行緒的幾種實現方式,什麼是執行緒安全
    1)繼承Thread類建立執行緒
    2)實現Runnable介面建立執行緒
    3)實現Callable介面通過FutureTask包裝器來建立Thread執行緒
    4)執行緒安全理解:執行緒安全就是多執行緒訪問時,採用了加鎖機制,當一個執行緒訪問該類的某個資料時,進行保護,其他執行緒不能進行訪問直到該執行緒讀取完,其他執行緒才可使用。不會出現資料不一致或者資料汙染。

14、執行緒的生命週期和各種狀態變化
    1)多執行緒理解:當執行緒被建立並啟動以後,它既不是一啟動就進入了執行狀態,也不是一直處於執行狀態。線上程的生命週期中,它要經過新建(New)、就緒(Runnable)、執行(Running)、阻塞(Blocked)和死亡(Dead)5種狀態。尤其是當執行緒啟動以後,它不可能一直"霸佔"著CPU獨自執行,所以CPU需要在多條執行緒之間切換,於是執行緒狀態也會多次在執行、阻塞之間切換。
    2)各種狀態之間變化:
        1、 新建狀態:當程式使用new關鍵字建立了一個執行緒之後,該執行緒就處於新建狀態,此時僅由JVM為其分配記憶體,並初始化其成員變數的值
        2、就緒狀態:當執行緒物件呼叫了start()方法之後,該執行緒處於就緒狀態。Java虛擬機器會為其建立方法呼叫棧和程式計數器,等待排程執行
        3、執行狀態:如果處於就緒狀態的執行緒獲得了CPU,開始執行run()方法的執行緒執行體,則該執行緒處於執行狀態
        4、阻塞狀態:當處於執行狀態的執行緒失去所佔用資源之後,便進入阻塞狀態
            4.1、當佔用CPU的時間片刻用完(Thread.yield()),執行緒進入到阻塞狀態;需要再一次被選中排程才能再次進入就緒狀態。
            4.2、當遇到了synchronized執行緒進入阻塞狀態,需要拿到物件所標記才能再次進入就緒狀態。
            4.3、當執行緒呼叫了某個物件的wait()方法時;也會使執行緒進入阻塞狀態;需要用notify()或者notifyall()方法來喚醒。
            4.4、一個執行緒呼叫了另一個執行緒的join()方法時,當前執行緒進入阻塞狀態。等新加入的執行緒執行結束後會結束阻塞狀態,進入就緒狀態。
            4.5、呼叫了Thread的sleep(long millis)。執行緒睡眠時間到了會自動進入就緒狀態。
            4.6、當遇到使用者輸入時候也會進入阻塞狀態;要等待使用者結束才能再次就緒狀態。
            4.7、執行緒從阻塞狀態只能進入就緒狀態,而不能直接進入執行狀態,即結束阻塞的執行緒需要重新進入可執行池中,等待系統的排程。
        5、死亡狀態:執行緒的run()方法正常執行完畢或者執行緒丟擲一個未捕獲的異常(Exception)、錯誤(Error),執行緒就進入死亡狀態。一旦進入死亡狀態,執行緒將不再擁有執行的資格,也不能轉換為其他狀態。

15、sleep 和 wait 的區別
    1)代表意思不一樣:sleep是執行緒休眠,在呼叫sleep()方法的過程中,執行緒不會釋放物件鎖;時間結束就可以使執行緒進入執行狀態;wait是執行緒等待,執行緒會放棄物件鎖;需要用notify()或者notifyall()方法去喚醒使執行緒進入。
    2)所屬地方不同:sleep是Thread類的靜態方法;而wait是Object的方法。

16、用過執行緒池嗎?它的作用?newCache 和 newFixed 有什麼區別
    1)作用:限制系統中執行執行緒的數量;減少了建立和銷燬現成的次數;每個工作執行緒都有可以被重複利用;可執行多個任務。可以根據系統的承受能力,調整執行緒池中工作執行緒的數量,防止因為消耗過多的記憶體而把伺服器累趴下(每個執行緒需要大約1MB記憶體,執行緒開的越多,消耗的記憶體也就越大,最後宕機)。
    2)newSingleThreadExecutor:返回一個包含單執行緒的Executor,將多個任務交給它時候,它是單執行緒序列執行所有任務。這個執行緒處理完一個任務後接著處理下一個任務,若該執行緒出現異常,將會有一個新的執行緒來替代。此執行緒池保證所有任務的執行順序按照任務的提交順序執行。
    3)newFixedThreadPool:返回一個包含指定數目執行緒的執行緒池,如果任務數量多於執行緒數目,那麼沒有沒有執行的任務必須等待,直到有任務完成為止。
    4)newCachedThreadPool:建立一個可快取的執行緒池。如果執行緒池的大小超過了處理任務所需要的執行緒,那麼就會回收部分空閒(60秒不執行任務)的執行緒,當任務數增加時,此執行緒池又可以智慧的新增新執行緒來處理任務。此執行緒池不會對執行緒池大小做限制,執行緒池大小完全依賴於作業系統(或者說JVM)能夠建立的最大執行緒大小。可能引起記憶體不足。?底層是基於ThreadPoolExecutor實現,藉助reentrantlock保證併發。?coreSize核心執行緒數,maxsize最大執行緒數。?

17、談談java 同步機制的 wait 和 notify
    都只能再同步程式碼塊中執行;wait釋放鎖;notify喚醒。

18、synchronized 修飾靜態方法和非靜態方法有什麼區別
    類鎖和物件鎖?,那麼static獲取到的鎖,是屬於類的鎖。而非static方法獲取到的鎖,是屬於當前物件的鎖。所以,他們之間不會產生互斥。

**19、導致執行緒死鎖的原因?怎麼解除執行緒死鎖。
    死鎖問題是多執行緒特有的問題,它可以被認為是執行緒間切換消耗系統性能的一種極端情況。在死鎖時,執行緒間相互等待資源,而又不釋放自身的資源,導致無窮無盡的等待,其結果是系統任務永遠無法執行完成。死鎖問題是在多執行緒開發中應該堅決避免和杜絕的問題。?
    一般來說,要出現死鎖問題需要滿足以下條件:?
        1)互斥條件:一個資源每次只能被一個執行緒使用。?
        2)請求與保持條件:一個程序因請求資源而阻塞時,對已獲得的資源保持不放。?
        3)不剝奪條件:程序已獲得的資源,在未使用完之前,不能強行剝奪。?
        4)迴圈等待條件:若干程序之間形成一種頭尾相接的迴圈等待資源關係。?
    只要破壞死鎖 4 個必要條件之一中的任何一個,死鎖問題就能被解決。

19、位元組流和字元流的區別
    1)位元組流操作的基本單元為位元組,採用ASCII編碼;字元流操作的基本單元為Unicode碼元。
    2)位元組流預設不使用緩衝區;字元流使用緩衝區。
    3)位元組流通常用於處理二進位制資料,實際上它可以處理任意型別的資料,但它不支援直接寫入或讀取Unicode碼元;字元流通常處理文字資料,它支援寫入及讀取Unicode碼元

20、Http狀態碼有哪些
    200 – 請求成功;301 – 資源(網頁等)被永久轉移到其它URL;404 – 請求的資源(網頁等)不存在;500 – 內部伺服器錯誤
    1**資訊:伺服器收到請求,需要請求者繼續執行操作(100Continue繼續。客戶端應繼續其請求)
    2**成功:操作被成功接收並處理(200 – 請求成功)
    3**重定向:需要進一步的操作以完成請求(301 – 資源(網頁等)被永久轉移到其它URL)
    4**客戶端錯誤:請求包含語法錯誤或無法完成請求(404 – 請求的資源(網頁等)不存在)
    5**伺服器錯誤:伺服器在處理請求的過程中發生了錯誤(500 – 內部伺服器錯誤)

21、Http協議中TCP三次握手和四次揮手的流程
    三次握手:首先Client端傳送連線請求報文,Server段接受連線後回覆ACK=1的報文,併為這次連線分配資源。Client端接收到ACK報文後也向Server段發出ACK=(服務的seq+1)的報文,並分配資源,這樣TCP連線就建立了。
        1)連線請求(SYN=1, seq=x):客戶端向伺服器傳送一個 TCP 的 SYN 標誌位置1的包,指明客戶端打算連線的伺服器的埠,以及儲存在包頭的序列號(Sequence Number)欄位裡初始序號X。
        2)授予連線(給出響應;SYN=1, ACK=1, seq=y, ACKnum=x+1):伺服器給客戶端給出響應;伺服器發回確認包(ACK)應答。即 SYN 標誌位和 ACK 標誌位均為1。伺服器端選擇自己 ISN 序列號,放到 Seq 域裡,同時將確認序號(Acknowledgement Number)設定為客戶的 ISN 加1,即X+1。
        3)確認連線(ACK=1,ACKnum=y+1):客戶端再次傳送確認包(ACK),SYN 標誌位為0,ACK 標誌位為1,並且把伺服器發來 ACK 的序號欄位+1,放在確定欄位中傳送給對方,並且在資料段放寫ISN的+1
傳送完畢後,客戶端進入?ESTABLISHED?狀態,當伺服器端接收到這個包時,也進入?ESTABLISHED?狀態,TCP 握手結束。
        
    四次揮手:
        1)傳送關閉請求(FIN=1,seq=x):客戶端傳送一個 FIN 標誌位置為1的包,表示自己已經沒有資料可以傳送了,但是仍然可以接受資料。傳送完畢後,客戶端進入 FIN_WAIT_1 狀態。
        2)給出響應(ACK=1,ACKnum=x+1):伺服器端確認客戶端的 FIN 包,傳送一個確認包,表明自己接受到了客戶端關閉連線的請求,但還沒有準備好關閉連線。傳送完畢後,伺服器端進入 CLOSE_WAIT 狀態,客戶端接收到這個確認包之後,進入 FIN_WAIT_2 狀態,等待伺服器端關閉連線。
        3)伺服器準備關閉(FIN=1,seq=y):伺服器端準備好關閉連線時,向客戶端傳送結束連線請求,FIN 置為1。傳送完畢後,伺服器端進入 LAST_ACK 狀態,等待來自客戶端的最後一個ACK。
        4)客戶端確認關閉(ACK=1,ACKnum=y+1):客戶端接收到來自伺服器端的關閉請求,傳送一個確認包,並進入 TIME_WAIT狀態,等待可能出現的要求重傳的 ACK 包。伺服器端接收到這個確認包之後,關閉連線,進入 CLOSED 狀態。客戶端等待了某個固定時間(兩個最大段生命週期,2MSL,2 Maximum Segment Lifetime)之後,沒有收到伺服器端的 ACK ,認為伺服器端已經正常關閉連線,於是自己也關閉連線,進入 CLOSED 狀態。?
    【問題1】為什麼連線的時候是三次握手,關閉的時候卻是四次握手?
        答:因為當Server端收到Client端的SYN連線請求報文後,可以直接傳送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連線時,當Server端收到FIN報文時,很可能並不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。只有等到我Server端所有的報文都發送完了,我才能傳送FIN報文,因此不能一起傳送。故需要四步握手。
    【問題2】為什麼TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?
        答:雖然按道理,四個報文都發送完畢,我們可以直接進入CLOSE狀態了,但是我們必須假象網路是不可靠的,有可以最後一個ACK丟失。所以TIME_WAIT狀態就是用來重發可能丟失的ACK報文。

21、Http協議中Get和Post請求方式的區別
    1)請求報文格式不同:即Get使用Url或cookie傳引數,而post使用body傳引數
    2)對資料的長度限制不同:get的url會有長度限制(最大2048個字元),而Post資料則可以不受url的限制,可以很大
    3)對資料型別限制不同:GET只允許ASCII碼字元;POST沒有限制;也可以是二進位制資料
    4)安全性不同:post比get安全,因為傳遞引數在url中不可見;
    5)細分用途不同:get請求主要用於獲取、查詢資源資訊;post請求,更新資料,一般要到form(表單),比較麻煩。
    6)響應速度不同:GET速度快;POST速度慢

22、簡單介紹一下AJAX?作用是什麼?使用場景?
    1)什麼是AjAx:非同步的javascript和xml。
    2)作用是什麼:通過AjAx與伺服器進行資料交換,AjAx可以使用網頁實現佈局更新。這意味著可以在不重新載入整個網頁的情況下,對網頁的某部分進行更新。
    3)怎麼來實現Ajax:XmlHttpRequest物件,使用這個物件可以異步向伺服器傳送請求,獲取響應更新,完成區域性更新。?Open send responseText/responseXML?區域性響應。
    4)使用場景:登入失敗不跳轉頁面。註冊實時提示使用者名稱是否存在。省市區的聯動。管理圖片伺服器,進行延時載入

23、Ajax怎麼訪問SpringMVC返回JSON格式資料?
    前端傳JSON字串;後端用@ResponseBody接收。比如說當你實現一部登陸驗證的時候;如果返回一個JSON資料;那麼在success後面定義一個function(data)去接收它。

24、你對servlet的理解?或者servlet是什麼?
    1)servlet介面定義的是一套處理網路請求的規範,所有實現servlet的類,都需要實現它那五個方法,其中最主要的是兩個生命週期方法 init()和destroy(),還有一個處理請求的service();HttpServlet 重寫doGet和doPost方法或者可以重寫service方法完成對get和post請求的響應。
    2)Servlet必須存放在一個web容器中——這個容器就是一個WEB伺服器,tomcat就可以。
    3)把Servlet放到tomcat中以後,tomcat就是是與客戶端直接打交道的傢伙,他監聽了埠;HttpServletRequest請求過來後,根據url等資訊,確定要將請求交給哪個servlet去處理,然後呼叫那個servlet的service方法去處理;至於具體是get請求還是post請求它裡面自己去判斷;但是最終還是呼叫doGet()方法;方法返回一個HttpServletResponse物件,tomcat再把這個物件返回給客戶端。

25、servlet的工作原理與生命週期?
    1)工作原理:
        ①Servlet接收和響應客戶請求的過程,首先客戶傳送一個請求,Servlet是呼叫service()方法對請求進行響應的,service()方法中對請求的方式進行了匹配,選擇呼叫doGet,doPost等這些方法,然後再進入對應的方法中呼叫邏輯層的方法,實現對客戶的響應。我們每次定義一個Servlet的時候,都必須實現doGet或doPost等這些方法。
        ②Servlet沒有主方法,不能夠獨立的執行,它的執行需要容器的支援,Tomcat是最常用的JSP/Servlet容器。Servlet執行在Servlet容器中,並由容器管理從建立到銷燬的整個過程。這時就有了Servlet的生命週期。
    2)生命週期:
        ①Servlet生命週期分為四個部分:1.載入和例項化 ->2.初始化 - > 3.請求處理 -> 4.銷燬
        ②Servlet中三個方法涉及到Servlet的生命週期,分別是init(),service(),destroy()方法。
        ③具體實現:
            1.載入和例項化:當檢測到需要Servlet的第一個請求時,讀取xml檔案找到要載入的servlet類,建立Servlet例項。?載入一般是在執行tomcat容器時來完成,將servlet類載入到tomcat中,或者是客戶端發來請求時也可以
            2.初始化:也就是init()方法--->初始化資訊一般是讀取配置資訊、讀取初始化引數等,對於每一個servlet例項,inin()方法值被呼叫一次。就是在使用者第一次請求到來的時候執行,如果不配置load-on-startup;那麼該servlet會在請求第一次到來初始化。如果配置了初始化的相關操作【load-on-startup】會在伺服器啟動時候執行;如果設定了多個那麼servlet加    載的優先順序設定的值越小優先順序越高。
            3.請求處理:也就是service()方法--->呼叫Servlet的service()方法對請求進行處理,在呼叫該方法之前,init()方法必須先成功執行。每次請求到來都會執行,並且在init()方法之後執行。可以不用重寫這個方法,因為父類已經很好的實現了service()方法;會自動根據提交方式的不同調用以之對應的doGet()或者duPost()方法。
            4.銷燬:也就是destroy()方法--->作用回收關閉相關資源;在更新程式碼時候執行。整個Servlet的生命週期結束。一般tomcat關閉,servlet就會被銷燬。

26、forward()與redirect()的區別?
    1)從位址列顯示來說 :forward(請求轉發)位址列不變直接跳轉要訪問的頁面;redirect(重定向)位址列發生改變,變成要訪問的那個URL
    2)從安全性來說:forward比redirect安全
    3)從資料共享來說 :forward轉發頁面和轉發到的頁面可以共享request裡面的資料.redirect不能共享資料.        
    4)從運用地方來說 :forward一般用於使用者登陸的時候,根據角色轉發到相應的模組;redirect一般用於使用者登出登陸時返回主頁面和跳轉到其它的網站等.
    5)從效率來說 :forward效率比redirect高
    6)從本質上來說:redirect兩次請求兩次響應;forward一次請求一次響應

27、jsp有哪些內建物件?作用分別是什麼?
    1)request物件:request物件代表了客戶端的請求資訊,主要用於接受通過HTTP協議傳送到伺服器的資料。(包括頭資訊、系統資訊、請求方式以及請求引數等)。request物件的作用域為一次請求。
    2)response物件:response 代表的是對客戶端的響應,主要是將JSP容器處理過的物件傳回到客戶端。response物件也具有作用域,它只在JSP頁面內有效。
    3)session物件(一次會話):session 物件是由伺服器自動建立的與使用者請求相關的物件。伺服器為每個使用者都生成一個session物件,用於儲存該使用者的資訊,跟蹤使用者的操作狀態。session物件內部使用Map類來儲存資料,因此儲存資料的格式為 “Key/value”。 session物件的value可以使複雜的物件型別,而不僅僅侷限於字串型別。
    4)application物件(屬於系統級別):application 物件可將資訊儲存在伺服器中,直到伺服器關閉,否則application物件中儲存的資訊會在整個應用中都有效。與session物件相比,application物件生命週期更長,類似於系統的“全域性變數”。
    5)out 物件:out 物件用於在Web瀏覽器內輸出資訊,並且管理應用伺服器上的輸出緩衝區。在使用 out 物件輸出資料時,可以對資料緩衝區進行操作,及時清除緩衝區中的殘餘資料,為其他的輸出讓出緩衝空間。待資料輸出完畢後,要及時關閉輸出流。
    6)pageContext 物件:pageContext 物件的作用是取得任何範圍的引數,通過它可以獲取 JSP頁面的out、request、reponse、session、application 等物件。pageContext物件的建立和初始化都是由容器來完成的,在JSP頁面中可以直接使用 pageContext物件。
    7)config 物件:config 物件的主要作用是取得伺服器的配置資訊。通過 pageConext物件的getServletConfig() 方法可以獲取一個config物件。當一個Servlet 初始化時,容器把某些資訊通過 config物件傳遞給這個 Servlet。 開發者可以在web.xml 檔案中為應用程式環境中的Servlet程式和JSP頁面提供初始化引數。
    8)page 物件:page 物件代表JSP本身,只有在JSP頁面內才是合法的。 page隱含物件本質上包含當前 Servlet介面引用的變數,類似於Java程式設計中的 this 指標。
    9)exception 物件:exception 物件的作用是顯示異常資訊,只有在包含 isErrorPage="true" 的頁面中才可以被使用,在一般的JSP頁面中使用該物件將無法編譯JSP檔案。excepation物件和Java的所有物件一樣,都具有系統提供的繼承結構。exception 物件幾乎定義了所有異常情況。在Java程式中,可以使用try/catch關鍵字來處理異常情況; 如果在JSP頁面中出現沒有捕獲到的異常,就會生成 exception 物件,並把 exception 物件傳送到在page指令中設定的錯誤頁面中,然後在錯誤頁面中處理相應的 exception 物件。

28、session工作原理
    同一個session會話的ID相同。使用者第一次請求的時候伺服器會響應返回一個sessionID;Servlet如果沒有從請求中發現sessionID那麼會建立一個新的sessionID;sessionID響應的時候交給瀏覽器,瀏覽器會將sessionID儲存在本地瀏覽器Cookie中。伺服器中有一個Map<String,Map>來儲存sessionID和session繫結的資料。且以後每一次傳送請求時都會附帶這個ID。(Cookie主要就是用來儲存資料的)

29、session和cookie的區別?
    1)Cookie和Session有很多相似的地方,都是用來臨時儲存來訪者資訊,有很多情況下,使用兩者都可以實現某些特定功能,而兩者的根本區別是Cookie物件將資訊存放在客戶端,Session物件存放在伺服器端;從生存期上講,Cookie可以長期儲存,而Session的生存期僅僅到會話結束。
    2)Cookie儲存在客戶端,使用者可以看到Cookie檔案,並能對Cookie檔案進行類似修改、刪除的操作,Cookie資料的安全性很難得到保障;而Session資料儲存在伺服器端,有較好的安全性,若和資料庫配合使用,可以使Session資料長期保持,並得到很好的安全性。

30、什麼是Spring框架?Spring框架有哪些主要模組?依賴注入的三種方式?
    1)Spring框架:Spring框架是一個為Java應用程式的開發提供了綜合、廣泛的基礎性支援的Java平臺。Spring幫助開發者解決了開發中基礎性的問題,使得開發人員可以專注於應用程式的開發。Spring框架本身亦是按照設計模式精心打造,這使得我們可以在開發環境中安心的整合Spring框架,不必擔心Spring是如何在後臺進行工作的。
    2)Spring主要模組:Spring框架至今已集成了20多個模組。有資料訪問/整合,、Web、AOP(面向切面程式設計)、工具、訊息和測試模組。
    3)SpringIOC依賴注入三種方式:構造器注入、setter方式注入、介面注入

31、Spring中的兩大核心機制?
    SpringIOC:
    1)控制反轉。由容器控制程式之間的關係,而非傳統實現中,由程式程式碼直接操控。控制權由應用程式碼中轉到了外部容器,控制權進行了轉移。控制反轉是將物件的生命週期控制權限交由Spring容器管理. 程式不再編寫物件建立語句,只使用物件. 這樣程式設計師的精力可以集中在業務開發中. 並且通過Spring容器實現了各層程式碼之間的解耦, 讓程式碼沒有依賴關係. 且實現了程式碼的可插拔性。所以這叫控制反轉。降低了業務物件之間替換的複雜性,使之能夠靈活的管理物件。(例如:病人、醫生、藥三者的關係)
    2)DI 依賴注入 實現:DI依賴注入:說的是建立物件例項時,為這個物件注入屬性值或其它物件例項,側重於實現。
    SpringAOP:面向切面程式設計;(在傳統的面向物件(Object-Oriented Progr amming,OOP)程式設計中,對垂直切面關注度很高,橫切面關注卻很少,也很難關注。也就是說,我們利用OOP思想可以很好的處理業務流程,卻不能把系統中的某些特定的重複性行為封裝在某個模組中。比如在很多的業務中都需要記錄操作日誌,結果我們不得不在業務流程種嵌入大量的日誌記錄程式碼。無論是對業務 程式碼還是對日誌記錄程式碼來說,今後的維護都是非常複雜的。由於系統種嵌入了這種大量的與業務無關的其它重複性程式碼,系統的複雜性、程式碼的重複性增加了,從而使bug的發生率也大大的增加。) 那麼什麼可以解決這個問題呢?這時候,我們需要AOP,關注系統的“截面”,在適當的時候“攔截”程式的執行流程,把程式的預處理和後處理交給某個攔截器 來完成。比如在操作資料庫時要記錄日誌,如果使用AOP的程式設計思想,那麼我們在處理業務流程時不必再考慮日誌記錄,而是把它交給一個特定的日誌記錄模組去 完成。這樣,業務流程就完全的從其它無關的程式碼中解放出來,各模組之間的分工更加明確,程式維護也變得容易多了。
    SpringAOP概念:
        1)Aspect(切面):通常是一個類,裡面可以定義切入點和通知
        2)JointPoint(連線點):程式執行過程中明確的點,一般是方法的呼叫
        3)Pointcut(切入點):就是帶有通知的連線點,在程式中主要體現為書寫切入點表示式
        4)AOP代理:AOP框架建立的物件,代理就是目標物件的加強。Spring中的AOP代理可以使JDK動態代理,也可以是CGLIB代理,前者基於介面,後者基於子類
        5)通知(advice):AOP在特定的切入點上執行的增強處理目前AOP定義了五種通知:
        前置通知(Before advice):在目標方法被呼叫之前呼叫通知功能。
        後置通知(After advice):在被通知的方法呼叫之前和呼叫之後執行自定義的行為。
        環繞通知(Around Advice):在目標方法成功執行之後呼叫通知。
        異常通知(After throwing advice):在目標方法丟擲異常後呼叫通知。
        返回後通知(After returning advice):在目標方法完成之後呼叫通知,此時不會關心方法的輸出是什麼。

32、Spring中怎麼實現AOP?
    1)實現AOP的技術:1.靜態代理(編譯時增強)AspectJ
                優點: 不改變目標物件程式碼,實現擴充套件功能
                 缺點: 代理物件和目標物件,需要實現同一個介面
                       2.動態代理(執行時增強)JDK動態代理與cglib代理
    2)Spring實現AOP:JDK動態代理和CGLIB代理
            JDK動態代理:其代理物件必須是某個介面的實現,它是通過在執行期間建立一個介面的實現類來完成對目標物件的代理;其核心的兩個類是InvocationHandler和Proxy。
            動態代理 - 在記憶體中建立代理物件,讓代理物件實現和目標物件相同的介面
             jdk代理 - 使用到jdk內部Proxy類
              介面代理 - 目標物件必須實現介面
              優點: 1.不改變目標物件程式碼,實現擴充套件功能
                    2.代理物件和目標物件,不需要實現同一個介面
              缺點: 目標物件,需要實現介面
                 CGLIB代理:實現原理類似於JDK動態代理,只是它在執行期間生成的代理物件是針對目標類擴充套件的子類。CGLIB是高效的程式碼生成包,底層是依靠ASM(開源的java位元組碼編輯類庫)操作位元組碼實現的,效能比JDK強;需要引入包asm.jar和cglib.jar。只需要一個介面;不需要目標物件與實現類,通過CGlib庫來建立目標物件的代理物件。建立代理物件,其實是在執行創建出來目標物件的子類的物件例項。

33、Spring Bean的作用域之間有什麼區別?
    Spring容器中的bean可以分為5個範圍
    1)singleton:這種bean範圍是預設的,這種範圍確保不管接受到多少個請求,每個容器中只有一個bean的例項,單例的模式由bean factory自身來維護。
    2)prototype:原形範圍與單例範圍相反,為每一個bean請求提供一個例項。
    3)request:在請求bean範圍內會每一個來自客戶端的網路請求建立一個例項,在請求完成以後,bean會失效並被垃圾回收器回收。
    4)Session:與請求範圍類似,確保每個session中有一個bean的例項,在session過期後,bean會隨之失效。
    5)global-session:global-session和Portlet應用相關。當你的應用部署在Portlet容器中工作時,它包含很多portlet。如果你想要宣告讓所有的portlet共用全域性的儲存變數的話,那麼這全域性變數需要儲存在global-session中。全域性作用域與Servlet中的session作用域效果相同。

34、Spring 框架中都用到了哪些設計模式?
    1)代理模式—在AOP和remoting中被用的比較多。
    2)單例模式—在spring配置檔案中定義的bean預設為單例模式。
    3)模板方法—用來解決程式碼重複的問題。比如.?RestTemplate,?JmsTemplate,?JpaTemplate。
    4)前端控制器—Spring提供了DispatcherServlet來對請求進行分發。
    5)檢視幫助(View Helper?)—Spring提供了一系列的JSP標籤,高效巨集來輔助將分散的程式碼整合在視圖裡
    6)依賴注入—貫穿於BeanFactory?/?ApplicationContext介面的核心理念。
    7)工廠模式—BeanFactory用來建立物件的例項。

35、SpringMVC請求流程
    (1)客戶端傳送請求到DispathcherServlet;最終呼叫doDispatch()方法
    (2)前端控制器呼叫處理器對映器查詢Handler;呼叫getHandler()方法;也就是通過HandlerMapping來獲取到HandlerExecutionChain;其中包含執行控制器Controller
    (3)通過HandlerExecutionChain呼叫處理器介面卡【呼叫getHandlerAdatpter()方法】來獲取HandlerAdatpter
    (4)再通過HandlerAdatpter來呼叫invoke方法,來呼叫控制器方法,會得到一個ModelAndView物件
    (5)解析檢視,通過檢視解析器解析檢視,呼叫ViewResolver方法生成View物件,View物件中包含要渲染檢視的地址
    (6)渲染檢視: 把模型中資料新增到請求作用域,跳轉到檢視頁面【用View呼叫render()方法】;最後響應給客戶端

36、SpringMVC怎麼樣設定重定向和轉發?
    (1)返回的結果使用 redirect  "redirect:/products "【表示重定向;位址列會跟著變化】
    (2)返回的結果使用 forward  "forward: /products"【表示請求轉發;位址列不會跟著變化】

37、SpringMVC攔截器的作用和使用場景?
    1)攔截器作用:就是攔截WEB請求,類似於Filter。Filter主要針對請求過濾,攔截器主要針對控制器進行攔截。主要是攔截控制器的方法執行(preHandle -> postHandle -> afterCompletion)
    2)定義攔截器
        1. 實現HandlerIntercepter介面
            boolean preHandle()
                在控制器方法執行前,如果返回false,就不會執行控制方法
            void postHandle()
                在控制器方法執行後執行
            void afterCompletion()
                在檢視解析並且渲染後執行
        2. 繼承HandlerIntercepterAdapter類
    3) 配置攔截器
        1. 攔截所有的請求
            <mvc:intercepters>
                <bean class="攔截器類名"/>
                <ref bean="攔截器名稱"/>
            </mvc:intercepters>
        
        2. 自定義攔截的路徑
            <mvc:intercepters>
                <mvc:intercepter>
                    <mvc:include path="攔截路徑"/>
                    <mvc:exclude path="排除攔截路徑"/>
                    <bean class="攔截器類名"/>
                </mvc:intercepter>
            </mvc:intercepters>
    4)攔截器應用
        1.攔截使用者是否登入
        2.攔截上傳檔案型別是否正確

38、攔截器(SpringMVC)和過濾器區別?
    1)過濾器:依賴於servlet容器。在實現上基於函式回撥,可以對幾乎所有請求進行過濾,但是缺點是一個過濾器例項只能在容器初始化時呼叫一次。使用過濾器的目的是用來做一些過濾操作,獲取我們想要獲取的資料.
    2)攔截器:依賴於web框架,在SpringMVC中就是依賴於SpringMVC框架。在實現上基於Java的反射機制,屬於面向切面程式設計(AOP)的一種運用。由於攔截器是基於web框架的呼叫.因此可以使用spring的依賴注入(DI)進行一些業務操作,同時一個攔截器例項在一個controller生命週期之內可以多次呼叫。但是缺點是隻能對controller請求進行攔截,對其他的一些比如直接訪問靜態資源的請求則沒辦法進行攔截處理。
    3)執行順序:過濾器的執行是依賴於servlet容器的,跟springmvc等框架並沒有關係。並且多個過濾器的執行順序跟web.xml檔案中定義的先後關係有關。攔截器的執行順序跟在SpringMVC的配置檔案中定義的先後順序有關。

39、事務的四個基本特徵?
    資料庫事務transanction正確執行的四個基本要素。ACID,原子性(Atomicity)、一致性(Correspondence)、隔離性(Isolation)、永續性(Durability)。
    1)原子性:整個事務中的所有操作,要麼全部完成,要麼全部不完成,不可能停滯在中間某個環節。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一
樣。
    2)一致性:在事務開始之前和事務結束以後,資料庫的完整性約束沒有被破壞。
    3)隔離性:隔離狀態執行事務,使它們好像是系統在給定時間內執行的唯一操作。如果有兩個事務,執行在相同的時間內,執行?相同的功能,事務的隔離性將確保每一事務在系統中認為只有該事務在使用系統。
這種屬性有時稱為序列化,為了防止事務操作間的混淆,必須序列化或序列化請?求,使得在同一時間僅有一個請求用於同一資料。
    4)永續性:在事務完成以後,該事務所對資料庫所作的更改便持久的儲存在資料庫之中,並不會被回滾。

40、Spring的事務的傳播特性?
    1)Propagation.REQUIED:如果不存在事務,則開啟新的事務,否則使用原來的事務
    2)Propagation.REQUIES_NEW:無論如何都開啟新的事務
    3)Propagation.SUPPORTS:如果存在事務,則使用原來的事務,否則使用本地事務(丟擲異常無影響)
    4)Propagation.NOT_SUPPORTS:無論如何都使用本地事務(丟擲異常無影響)
    5)Propagation.MANDATORY:自身不開啟事務,必須在事務環境使用否則報錯
    6)Propagation.NEVER:自身不會開啟事務,在事務範圍使用丟擲異常
    7)Propagation.NESTED:和Propagation.REQUIED相似

41、Spring事務的隔離級別?Mysql預設隔離級別是什麼?
    1)讀未提交 Read Uncommited:意思就是即使一個更新語句沒有提交,但是別的事務可以讀到這個改變.這是很不安全的。允許任務讀取資料庫中未提交的資料更改,也稱為髒讀。
    2)讀已提交 Read Commited:可防止髒讀,意思就是語句提交以後即執行了COMMIT以後
別的事務就能讀到這個改變. 只能讀取到已經提交的資料。但是不可重複讀
    3)可重複讀 Repeated Read:這是說在同一個事務裡面先後執行同一個查詢語句的時候,得到的結果是一樣的.在同一個事務內的查詢都是事務開始時刻一致的,InnoDB預設級別。在SQL標準中,該隔離級別消除了不可重複讀,但是還存在幻象讀
    4)序列化 Serializable:意思是說這個事務執行的時候不允許別的事務併發執行. 完全序列化的讀,每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞
    實際開發,隔離級別設定為Read Commited
    Mysql預設隔離級別:可重複讀 Repeated Read
    orecle預設隔離級別:讀已提交 Read Commited
    
42、什麼是幻讀,哪種隔離級別可以防止幻讀?

    例如:目前工資為5000的員工有10人,事務A讀取所有工資為5000的人數為10人。此時,事務B插入一條工資也為5000的記錄。這時,事務A再次讀取工資為5000的員工,記錄為11人。此時產生了幻讀。
    可重複讀 Repeated Read:這是說在同一個事務裡面先後執行同一個查詢語句的時候,得到的結果是一樣的.在同一個事務內的查詢都是事務開始時刻一致的,InnoDB預設級別。在SQL標準中,該隔離級別消除了不可重複讀,但是還存在幻象讀
    防止幻讀:把隔離級別升級為序列化 Serializable:意思是說這個事務執行的時候不允許別的事務併發執行. 完全序列化的讀,每次讀都需要獲得表級共享鎖,讀寫相互都會阻塞

43、簡單談一下MyBatis?
    ORM框架,簡化JDBC處理,可以實現關係表和物件之間對映。
    優點:
    1. 易於上手和掌握。
    2. sql寫在xml裡,便於統一管理和優化。
    3. 解除sql與程式程式碼的耦合。
    4. 提供對映標籤,支援物件與資料庫的orm欄位關係對映
    5. 提供物件關係對映標籤,支援物件關係組建維護
    6. 提供xml標籤,支援編寫動態sql。
    缺點:
    1. sql工作量很大,尤其是欄位多、關聯表多時,更是如此。
    2. sql依賴於資料庫,導致資料庫移植性差。
    3. 由於xml裡標籤id必須唯一,導致DAO中方法不支援方法過載。
    4. 欄位對映標籤和物件關係對映標籤僅僅是對對映關係的描述,具體實現仍然依賴於sql。(比如配置了一對多Collection標籤,如果sql裡沒有join子表或查詢子表的話,查詢後返回的物件是不具備物件關係的,即Collection的物件為null)
    5. DAO層過於簡單,物件組裝的工作量較大。
    6.  不支援級聯更新、級聯刪除。
    7. 編寫動態sql時,不方便除錯,尤其邏輯複雜時。
    8 提供的寫動態sql的xml標籤功能簡單(連struts都比不上),編寫動態sql仍然受限,且可讀性低。
    9. 若不查詢主鍵欄位,容易造成查詢出的物件有“覆蓋”現象。
    10. 引數的資料型別支援不完善。(如引數為Date型別時,容易報沒有get、set方法,需在引數上加@param)
    11. 多引數時,使用不方便,功能不夠強大。(目前支援的方法有map、物件、註解@param以及預設採用012索引位的方式)
    12. 快取使用不當,容易產生髒資料。

44、#{}和${}的區別是什麼?
    #{}是預編譯處理,${}是字串替換。Mybatis在處理#{}時,會將sql中的#{}替換為?號,呼叫PreparedStatement的set方法來賦值;Mybatis在處理${}時,就是把${}替換成變數的值。使用#{}可以有效的防止SQL注入,提高系統安全性。

45、MyBatis中如何獲取自動生成的(主)鍵值?
    再Mapper配置檔案中:插入語句節點中;把是否生成主鍵(usegeneratedkeys)設定為true,然後再設定一個去接收主鍵值的名字(keyproperty=”id”);和物件的成員變數一樣吧!
        <insert id=”insertname” usegeneratedkeys=”true” keyproperty=”id”>
                 insert into names (name) values (#{name})
         </insert>
    
46、mapper中如何傳遞多個引數?
    1)DAO層的函式
        Public UserselectUser(String name,String area);
         對應的xml,#{0}代表接收的是dao層中的第一個引數,#{1}代表dao層中第二引數,更多引數一致往後加即可。
    <select id="selectUser"resultMap="BaseResultMap">  
            select *  fromuser_user_t   whereuser_name = #{0} anduser_area=#{1}  
    </select>
    2)使用 @param 註解:
        import org.apache.ibatis.annotations.param;
        public interface usermapper {
         user selectuser(@param(“username”) string username,
                    @param(“hashedpassword”) string hashedpassword);
        }
         然後,就可以在xml像下面這樣使用(推薦封裝為一個map,作為單個引數傳遞給mapper):
        <select id=”selectuser” resulttype=”user”>
                     select id, username, hashedpassword
                     from some_table
                     where username = #{username}
                     and hashedpassword = #{hashedpassword}
        </select>
    3)直接傳遞一個map<String,Object>集合

47、Mybatis一對一、一對多的關聯對映和查詢 ?
    1)一對一使用association節點進行關係對映
        在resultMap中配置association進行一對一的關係對映
        <resultMap type="Orders" id="OrderWithUserResultMap">
            <!-- 先Order對映配置 -->
            <id column="id" property="id"/>
            <result column="number" property="number"/>
            <result column="createtime" property="createTime"/>
            <result column="note" property="note"/>
            <!-- 再通過association來配置關聯的user屬性的對映內容 -->
            <!-- 配置使用者物件的對映資訊 -->
            <!-- <association property="user" javaType="User">
                <result column="username" property="username"/>
                <result column="birthday" property="birthday"/>
                <result column="sex" property="sex"/>
                <result column="address" property="address"/>
            </association> -->
            <!-- 配置使用者物件的對映資訊 -->
            <!-- 分離ResultMap -->
            <association property="user" javaType="User" resultMap="UserMap"/>
        </resultMap>
    2)一對多使用Conllection節點進行關係對映
        在resultMap中配置conllection進行一對多的關係對映
        <resultMap type="Orders" id="OrderWithUserResultMap">
            <!-- 先Order對映配置 -->
            <id column="id" property="id"/>
            <result column="number" property="number"/>
            <result column="createtime" property="createTime"/>
            <result column="note" property="note"/>
            <!-- 再通過association來配置關聯的user屬性的對映內容 -->
            <!-- 配置使用者物件的對映資訊 -->
            <collection property="集合屬性名" ofType="別名或者類全路徑">
                <id property="id" column="ooid"/>
                <result property="itemsId" column="items_id"/>
                <result property="itemsNum" column="items_num"/>
            </collection>
        </resultMap>

48、MyBatis的一級快取和二級快取?
    一級快取預設是開啟的;二級快取需要使用者自己開啟。有二級快取先利用二級快取
    1)Mybatis首先去快取中查詢結果集,如果沒有則查詢資料庫,如果有則從快取取出返回結果集就不走資料庫。
    2)Mybatis內部儲存快取使用一個HashMap,key為hashCode+sqlId+Sql語句。value為從查詢出來對映生成的java物件
    3)Mybatis的二級快取即查詢快取,它的作用域是一個mapper的namespace,即在同一個namespace中查詢sql可以從快取中獲取資料。二級快取是可以跨SqlSession的。

49、請介紹關係資料庫三正規化?
    1)第一正規化(1NF):欄位具有原子性,不可再分。所有關係型資料庫系統都滿足第一正規化。資料庫表中的欄位都是單一屬性的,不可再分。
    2)第二正規化(2NF)是在第一正規化(1NF)的基礎上建立起來的,即滿足第二正規化(2NF)必須先滿足第一正規化(1NF)。第二正規化(2NF)要求資料庫表中的每個例項或行必須可以被惟一的區分。為實現區分通常需要為表加上一個列,以儲存各個例項的惟一標識。要求實體的屬性完全依賴於主關鍵字。簡而言之,第二正規化就是非主屬性部分依賴於主關鍵字。
    3)滿足第三正規化(3NF)必須先滿足第二正規化(2NF)。簡而言之,第三正規化(3NF)要求一個數據庫表中不包含已在其它表中已包含的非主關鍵字資訊。
    所以第三正規化具有如下特徵:
        1,每一列只有一個值
        2,每一行都能區分。
        3,每一個表都不包含其他表已經包含的非主關鍵字資訊。

50、請描述資料庫優化的思路?
    1.SQL語句優化
        1)應儘量避免在?where?子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。
        2)應儘量避免在?where?子句中對欄位進行?null?值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:select?id?from?t?where?num?is?null;可以在num上設定預設值0,確保表中num列沒有null值,然後這樣查詢:select?id?from?t?where?num=0
        3)很多時候用?exists?代替?in?是一個好的選擇
        4)用Where子句替換HAVING?子句
因為HAVING?只會在檢索出所有記錄之後才對結果集進行過濾
    2.索引優化:看上文索引
    3.資料庫結構優化
        1)正規化優化: ? ?比如消除冗餘(節省空間。。)
        2)反正規化優化:比如適當加冗餘等(減少join)
        3)拆分表:分割槽將資料在物理上分隔開,不同分割槽的資料可以制定儲存在處於不同磁碟上的資料檔案裡。這樣,當對這個表進行查詢時,只需要在表分割槽中進行掃描,而不必進行全表掃描,明顯縮短了查詢時間,另外處於不同磁碟的分割槽也將對這個表的資料傳輸分散在不同的磁碟I/O,一個精心設定的分割槽可以將資料傳輸對磁碟I/O競爭均勻地分散開。對資料量大的時時表可採取此方法。可按月自動建表分割槽。
        4)拆分其實又分垂直拆分和水平拆分:
    案例:簡單購物系統暫設涉及如下表:
    1.產品表(資料量10w,穩定)
    2.訂單表(資料量200w,且有增長趨勢)
    3.使用者表 (資料量100w,且有增長趨勢)
以mysql為例講述下水平拆分和垂直拆分,mysql能容忍的數量級在百萬靜態資料可以到千萬
    垂直拆分:
        解決問題:表與表之間的io競爭
        不解決問題:單表中資料量增長出現的壓力
    方案:
        把產品表和使用者表放到一個server上
        訂單表單獨放到一個server上
    水平拆分:
        解決問題:單表中資料量增長出現的壓力
        不解決問題:表與表之間的io爭奪
?
    方案:
        使用者表通過性別拆分為男使用者表和女使用者表
        訂單表通過已完成和完成中拆分為已完成訂單和未完成訂單
        產品表 未完成訂單放一個server上
        已完成訂單表盒男使用者表放一個server上
        女使用者表放一個server上
    4.伺服器硬體優化