萬物皆對象,把現實中有共同特性行爲的對象抽象成類,類是程序中最基本的單位。html
面向對象的思想是如何在java展示的呢? 就是經過類和對象前端
*類是 一組相關的屬性和行爲的集合。是一個抽象的概念。java
*對象 是該類事物的具體表現形式。具體存在的個體。mysql
類是對象的抽象,對象是類的實例。linux
*成員變量 事物的屬性程序員
*成員方法 事物的行爲web
Java的跨平臺是經過Java虛擬機JVM來實現的。不一樣的平臺須要安裝不一樣的虛擬機,java程序編譯以後的代碼不是能被硬件系統直接運行的代碼,而是一種「中間碼」——字節碼。而後不一樣的硬件平臺上安裝有不一樣的Java虛擬機(JVM),由JVM來把字節碼再「翻譯」成所對應的硬件平臺可以執行的代碼。ajax
JDK包含JRE,JRE包含JVMredis
JRE(JavaRuntimeEnvironment,Java運行環境),也就是Java平臺。全部的Java 程序都要在JRE下才能運行。普通用戶只須要運行已開發好的java程序,安裝JRE便可。算法
JDK(Java Development Kit)是程序開發者用來來編譯、調試java程序用的開發工具包。JDK的工具也是Java程序,也須要JRE才能運行。jre是jdk的一部分。爲了保持JDK的獨立性和完整性,在JDK的安裝過程當中,JRE也是 安裝的一部分。因此,在JDK的安裝目錄下有一個名爲jre的目錄,用於存放JRE文件。
JVM(JavaVirtualMachine,Java虛擬機)是JRE的一部分。它是一個虛構出來的計算機,是經過在實際的計算機上仿真模擬各類計算機功能來實現的。JVM有本身完善的硬件架構,如處理器、堆棧、寄存器等,還具備相應的指令系統。Java語言最重要的特色就是跨平臺運行。使用JVM就是爲了支持與操做系統無關,實現跨平臺。
GC是垃圾收集的意思(Gabage Collection),內存處理是編程人員容易出現問題的地方,忘記或者錯誤的內存回收會致使程序或系統的不穩定甚至崩潰,Java提供的GC功能能夠自動監測對象是否超過做用域從而達到自動回收內存的目的,Java語言沒有提供釋放已分配內存的顯示操做方法。
主要有如下四方面:
1.抽象:抽象就是找出一些事物的類似和共性之處,而後將這些事物歸爲一個類,這個類只考慮這些事物的類似和共性之處。抽象包括兩個方面,一是過程抽象,二是數據抽象。
2.繼承:子類繼承父類,子類共享父類屬性和方法的同時能夠擴展本身的屬性和方法。提升了軟件的可重用性和可擴展性 。
3.封裝:把對象的屬性和方法結合成一個總體,並隱藏內部的實現細節,提供對外的訪問接口。
4. 多態性:不一樣對象對同一消息作出不一樣的響應處理,主要實現:子類繼承父類,子類重寫父類的方法,父類的引用指向子類的對象。
面向過程
優勢:性能比面向對象高,由於類調用時須要實例化,開銷比較大,比較消耗資源;好比單片機、嵌入式開發、Linux/Unix等通常採用面向過程開發,性能是最重要的因素。
缺點:沒有面向對象易維護、易複用、易擴展
面向對象
優勢:易維護、易複用、易擴展,因爲面向對象有封裝、繼承、多態性的特性,能夠設計出低耦合的系統,使系統更加靈活、更加易於維護
缺點:性能比面向過程低
區別以下:
做用域 當前類 同一package 子孫類 其餘package
public √ √ √ √
protected √ √ √ ×
friendly √ √ × ×
private √ × × ×
不寫時默認爲friendly
&:」與」是位運算符,表示按位與運算,左邊是false右邊還執行。&&:」而且」是邏輯運算符,表示邏輯與(and),左邊是true右邊才執行
assertion(斷言)在軟件開發中是一種經常使用的調試方式,不少開發語言中都支持這種機制。在實現中,assertion就是在程序中的一條語句,它對一個boolean表達式進行檢查,一個正確程序必須保證這個boolean表達式的值爲true;若是該值爲false,說明程序已經處於不正確的狀態下,系統將給出警告或退出。通常來講,assertion用於保證程序最基本、關鍵的正確性。assertion檢查一般在開發和測試時開啓。爲了提升性能,在軟件發佈後,assertion檢查一般是關閉的
默認是關閉的,通常是測試的junit中用,判斷結果和本身的預想值是否一致。
java中的保留字,如今沒有在java中使用
String類是final類故不能夠繼承,final是最終的。
會執行,在return前執行
2 << 3:表示2向左移3位,由於一個數左移 n位,就至關於 2的 n次方,那麼一個數乘以 8只要將其左移 3位便可,而爲運算符的效率最高,因此 2乘以 8等於幾的最有效方法是 2<<3
不對,有相同的hash code,由於equals比較hash code值相同纔會返回true
是值傳遞。Java 編程語言只有值傳遞參數。
*值傳遞:是對所傳遞參數進行一次副本拷貝,對參數的修改只是對副本的修改,函數調用結束,副本丟棄,原來的變量不變(即實參不變),基本數據類型都是值傳遞。
*引用傳遞:參數被傳遞到函數時,不復制副本,而是直接將參數自身傳入到函數,函數內對參數的任何改變都將反映到原來的變量上。
*對於基本類型,傳遞的是基本類型的值,而對於引用類型傳遞的是地址。
在Java 5之前,switch(expr)中,expr只能是byte、short、char、int。從Java 5開始,Java中引入了枚舉類型,expr也能夠是enum類型,從Java 7開始,expr還能夠是字符串(String),可是長整型(long)在目前全部的版本中都是不能夠的。
String 是被final修飾的,長度是不可變的。StringBuffer和StringBuilder長度都是可變的
三者在執行速度方面的比較:StringBuilder > StringBuffer > String
若是要操做少許的數據用 String
單線程操做字符串緩衝區 下操做大量數據 = StringBuilder
多線程操做字符串緩衝區 下操做大量數據 = StringBuffer
StringBuffer是線程安全的有鎖,StringBuilder是線程不安全的,string是線程安全的由於final最終的。若是最後須要String,那麼使用StringBuffer的toString()方法
final—用於聲明屬性、類和方法,分別表示屬性不可變,方法不可覆蓋(重寫),類不可被繼承
finally—是異常處理語句結構的一部分,表示老是執行
finalize—是Object類的一個方法,在垃圾收集器執行的時候會調用被回收對象的此方法用於回收資源,能夠覆蓋此方法提供垃圾收集時的其餘資源回收,例如關閉文件等
棧是一種線形集合,其添加和刪除元素的操做應在同一段完成。棧按照先進後出的方式進行處理。棧是堆得組成元素,內存由堆,棧,池組成。堆是按照先進先出的原則。棧的空間由系統自動分配,堆的空間能夠本身分配。
棧至關於你往泡菜罈子裏裝泡菜,從裏面拿泡菜,先拿到的固然是上面的。也就是先進後出。堆(隊列)至關於一個隧道,火車往裏面開,不能回頭,頭先進去固然也先出來,這叫先進先出。
Java語言中一個顯著的特色就是引入了垃圾回收機制,垃圾回收能夠有效的防止內存泄露,有效的使用能夠使用的內存。
對於GC來講,當程序員建立對象時,GC就開始監控這個對象的地址、大小以及使用狀況。一般,GC採用有向圖的方式記錄和管理堆(heap)中的全部對象。經過這種方式肯定哪些對象是"可達的",哪些對象是"不可達的"。當GC肯定一些對象爲"不可達"時,GC就有責任回收這些內存空間。
回收機制有分代複製垃圾回收和標記垃圾回收,增量垃圾回收。
*分代複製垃圾回收:根據對象的生命週期不一樣,分爲年輕代、年老代、持久代,分區回收。
*標記垃圾回收:1、標記階段,標記全部可訪問對象;2、收集階段,標記垃圾回收算法回收首頁未標記的對象,在此過程當中會出現程序無響應。
*增量垃圾回收:主要是爲了解決標記垃圾回收時長停頓的問題,設置GC最多中斷的時間10ms,分時間段來回收垃圾。
JVM中類的裝載是由ClassLoader和它的子類來實現的,Java ClassLoader 是一個重要的Java運行時系統組件。它負責在運行時查找和裝入類文件的類。
1.裝載:查找和導入class文件;new對象隱式裝載,反射類顯示裝載,看log日誌就知道什麼是隱式/顯式
2.鏈接:
(1)檢查:檢查載入的class文件數據的正確性;
(2)準備:爲類的靜態變量分配存儲空間;
(3)解析:將符號引用轉換成直接引用(這一步是可選的)
3.初始化:初始化靜態變量,靜態代碼塊。
這樣的過程在程序調用類的靜態成員的時候開始執行,因此靜態方法main()纔會成爲通常程序的入口方法。類的構造器也會引起該動做。
能夠。只有一個public類,而且類名與文件名相同。
內存泄漏是指再也不被使用的對象或者變量一直被佔據在內存中。檢查java中的內存泄露,必定要讓程序將各類分支狀況都完整執行到程序結束,而後看某個對象是否被使用過,若是沒有,則才能斷定這個對象屬於內存泄露。
會。長生命週期的對象持有短生命週期對象的引用就有可能發生內存泄露。好比像加載了一個對象放在緩存中而一直沒有引用。
系統已經不能再分配出你所須要的空間,好比你須要100M的空間,系統只剩90M了,這就叫內存溢出。
內存泄露是對象沒有引用的時候沒有被回收,一直佔據着內存。
對於GC來講,當程序員建立對象時,GC就開始監控這個對象的地址、大小以及使用狀況。一般,GC採用有向圖的方式記錄和管理堆(heap)中的全部對象。經過這種方式肯定哪些對象是"可達的",哪些對象是"不可達的"。當GC肯定一些對象爲"不可達"時,GC就有責任回收這些內存空間。能夠。程序員能夠手動執行System.gc(),通知GC運行,可是Java語言規範並不保證GC必定會執行。
一、儘早釋放無用對象的引用
好的辦法是使用臨時變量的時候,讓引用變量在推出活動域後自動設置爲null,暗示垃圾收集器來收集該對象,防止發生內存泄漏。
二、程序進行字符串處理時,儘可能避免使用String,而應該使用StringBuffer。
由於String類是不可變的,每個String對象都會獨立佔用內存一塊區域。
三、儘可能少用靜態變量
由於靜態變量是全局的,存在方法區,GC不會回收。(用永久代實現的方法區,垃圾回收行爲在這個區域是比較少出現的,垃圾回收器的主要目標是針對常量池和類型的卸載)
四、避免集中建立對象,尤爲是大對象,若是能夠的話儘可能使用流操做
JVM會忽然須要大量neicun,這時會出發GC優化系統內存環境
五、儘可能運用對象池技術以提升系統性能
生命週期長的對象擁有生命週期短的對象時容易引起內存泄漏,例如大集合對象擁有大數據量的業務對象的時候,能夠考慮分塊進行處理,而後解決一塊釋放一塊的策略。
六、不要在常常調用的方法中建立對象,尤爲忌諱在循環中建立對象
能夠適當的使用hashtable,vector建立一組對象容器,而後從容器中去取這些對象,而不用每次new以後又丟棄。
七、優化配置
Java 內存溢出java.lang.OutOfMemoryError這個錯誤我相信大部分開發人員都有遇到過,產生該錯誤的緣由大都出於如下緣由:JVM內存太小、程序不嚴密,產生了過多的垃圾。
致使OutOfMemoryError異常的常見緣由有如下幾種:
內存中加載的數據量過於龐大,如一次從數據庫取出過多數據;
集合類中有對對象的引用,使用完後未清空,使得JVM不能回收;
代碼中存在死循環或循環產生過多重複的對象實體;
使用的第三方軟件中的BUG;
啓動參數內存值設定的太小;
1、增長jvm的內存大小。方法有:
1)在執行某個class文件時候,能夠使用java -Xmx256M aa.class來設置運行aa.class時jvm所容許佔用的最大內存爲256M。
2)對tomcat容器,能夠在啓動時對jvm設置內存限度。對tomcat,能夠在catalina.bat中添加:
set CATALINA_OPTS=-Xms128M -Xmx256M
set JAVA_OPTS=-Xms128M -Xmx256M
或者把%CATALINA_OPTS%和%JAVA_OPTS%代替爲-Xms128M -Xmx256M
3)對resin容器,一樣能夠在啓動時對jvm設置內存限度。在bin文件夾下建立一個startup.bat文件,內容以下:
@echo off
call "httpd.exe" "-Xms128M" "-Xmx256M"
:end
其中"-Xms128M"爲最小內存,"-Xmx256M"爲最大內存。
static i = 10; //常量 class A a; a.i =10;//可變
1)在語法定義上的區別:靜態變量前要加 static 關鍵字,而實例變量(成員變量)前則不加。
2)在程序運行時的區別:實例變量屬於某個對象的屬性,必須建立了實例對象,其中的實例變量纔會被分配空間,才能使用這個實例變量。
不能夠,若是其中包含對象的method();不能保證對象初始化.
java賦值是複製對象引用,若是咱們想要獲得一個對象的副本,就須要使用克隆clone()
Clone 有缺省行爲,super.clone();他負責產生正確大小的空間,並逐位複製。
類使用克隆:
① 實現Cloneable接口,這是一個標記接口,自身沒有方法。
② 對象.clone()方法獲得克隆對象,Person p1=new Person();Person p2=(Person) p1.clone();
用break; return 方法。
經常使用的類:BufferedReader BufferedWriter FileReader FileWirter String Integer
經常使用的包:java.lang java.awt java.io java.util java.sql
經常使用的接口:Remote List Map Document NodeList
*值傳遞:是對所傳遞參數進行一次副本拷貝,對參數的修改只是對副本的修改,函數調用結束,副本丟棄,原來的變量不變(即實參不變),基本數據類型都是值傳遞。
*引用傳遞:參數被傳遞到函數時,不復制副本,而是直接將參數自身傳入到函數,函數內對參數的任何改變都將反映到原來的變量上。
加載、驗證、準備、初始化、引用和卸載這六個過程
加載類,驗證語法,準備(分配內存),初始化(父子類構造函數,賦值),引用,卸載(垃圾回收)
a += 1這個和 a = a +1 這兩個是同樣的 只不過一個是簡寫
++a 和 a++ 這兩個區別在於運算的前後
好比:
b = ++a; 這個是a先自增 而後才賦值
b = a++; 這個是先賦值 後自增
①clone():protected Object clone()建立並返回此對象的一個副本。
②equals():boolean equals(Object obj)指示其餘某個對象是否與此對象「相等」。
③finalize():protected void finalize()當垃圾回收器肯定不存在對該對象的更多引用時,由對象的垃圾回收器調用此方法。
④getClass():Class<?> getClass()返回此 Object 的運行時類。
⑤hashCode():int hashCode()返回該對象的哈希碼值。
⑥notify():void notify()喚醒在此對象監視器上等待的單個線程。
⑦notifyAll():void notifyAll()喚醒在此對象監視器上等待的全部線程。
⑧toString():String toString()返回該對象的字符串表示。
⑨wait():void wait()在其餘線程調用此對象的 notify() 方法或 notifyAll() 方法前,致使當前線程等待。
void wait(long timeout)在其餘線程調用此對象的 notify() 方法或 notifyAll() 方法,或者超過指定的時間量前,致使當前線程等待。
void wait(long timeout, int nanos)在其餘線程調用此對象的 notify() 方法或 notifyAll() 方法,或者其餘某個線程中斷當前線程,或者已超過某個實際時間量前,致使當前線程等待。
裝箱:將值類型轉換爲引用類型的過程稱爲裝箱。int i=1; Object o=i
拆箱:將引用類型轉換爲值類型稱爲拆箱。int j=(int)o;
*順序結構:從上往下,依次執行
*選擇結構:if—else結構、switch結構
*循環結構:while、do while、for循環
值類型:8大數據類型
引用類型:數組、類、字符串、接口等
以值傳遞方式傳遞值類型參數時,對它的修改不會保留;以值傳遞方式傳遞引用類型參數時,其值的修改會保留。
以引用傳遞方式傳遞值類型參數和引用類型參數時,其值的修改都會保留。
java中會自動區分參數類型,所以沒有ref,所以沒有引用傳遞方式。
*矩形表示實體
*橢圓表示屬性
*菱形表示聯繫
*直線用來鏈接
基本數據類型包括整數型4種:byte(1字節8位)、short(2字節16位)、int(4字節32位)、long(8字節64位);浮點型2種:float(4季節32位)、double(8字節64位);布爾型一種:boolean(1字節8位);字符型一種:char(2字節16位)。
1字節=8位=8bit 1個漢子=2字節 這裏的位是指二進制的位數
java.lang.String類是final類型的,所以不能夠繼承這個類、不能修改這個類。爲了提升效率節省空間,咱們應該用StringBuffer類
Java 提供兩種不一樣的類型:引用類型和原始類型(或內置類型)。int是java的原始數據類型初始值是0,Integer是java爲int提供的封裝類,初始值是null。Java爲每一個原始類型提供了封裝類,8大數據類型首字母大寫就是封裝類。
數組沒有length()這個方法,有length的屬性。String有length()這個方法
兩個,一個字符對象,一個字符對象引用對象
答: Math.round(11.5)==12;Math.round(-11.5)==-11;round方法返回與參數最接近的長整數,參數加1/2後求其floor
short s1 = 1; s1 = s1 + 1; (s1+1運算結果是int型,須要強制轉換類型會報錯)short s1 = 1; s1 += 1;(能夠正確編譯)自動轉型小轉大,大轉小必須強制轉型
i=i+2 比 i+=2多了一次對變量 i 的運算。i=i+2是先進行i+2的運算得出一個結果,再賦值給i。i+=2就是先賦值而後在進行加法,所以運算效率高,結果是同樣的。
是可以定義成爲一箇中文的,由於java中以unicode編碼,一個char佔16個字節,因此放一箇中文是沒問題的
答:不正確。精度不許確,有小數點的默認是double,應該用強制類型轉換,以下所示:float f=(float)3.4或float f=3.4f
error 是不可控制的unchecked,用來表示系統錯誤或底層資源錯誤,若是有可能應該在系統級別被捕捉
exception 是可控的或不可控的(黑客攻擊),表示程序級的錯誤,應該在程序級別被捕捉
一、空指針異常類:NullPointerException
二、數據類型轉換異常:java.lang.ClassCastException
三、沒有訪問權限:java.lang.IllegalAccessException
四、方法的參數錯誤:java.lang.IllegalArgumentException
五、數組下標越界異常:java.lang.IndexOutOfBoundsException
六、文件已結束異常:EOFException
七、文件未找到異常:FileNotFoundException
八、字符串轉換爲數字異常:NumberFormatException
九、指定的類不存在: java.lang.ClassNotFoundException
十、實例化異常:java.lang.InstantiationException
異常表示程序運行過程當中可能出現的非正常狀態,運行時異常表示虛擬機的一般操做中可能遇到的異常,是一種常見運行錯誤。java編譯器要求方法必須聲明拋出可能發生的非運行時異常,可是並不要求必須聲明拋出未被捕獲的運行時異常。
出現運行時異常後,系統會把異常一直往上層拋,一直遇處處理代碼。若是沒有處理塊,到最上層,若是是多線程就由Thread.run() 拋出 ,若是是單線程就被 main() 拋出 。
原理:有錯直接轉到異常處理部分或向上拋出。
應用:JAVA 的異常就是錯誤,有兩種一種是運行時,編碼能夠不用捕捉。一種是通常異常,若是throws 聲明瞭,必須進行處理。
當JAVA程序違反了JAVA的語義規則時,JAVA虛擬機就會將發生的錯誤表示爲一個異常。違反語義規則包括2種狀況。一種是JAVA類庫內置的語義檢查。例如數組下標越界,會引起IndexOutOfBoundsException;訪問null的對象時會引起NullPointerException。另外一種狀況就是JAVA容許程序員擴展這種語義檢查,程序員能夠建立本身的異常,並自由選擇在什麼時候用throw關鍵字引起異常。全部的異常都是java.lang.Thowable的子類。
Java經過面向對象的方法進行異常處理,把各類不一樣的異常進行分類,並提供了良好的接口。在Java中,每一個異常都是一個對象,它是Throwable類或其它子類的實例。當一個方法出現異常後便拋出一個異常對象,該對象中包含有異常信息,調用這個對象的方法能夠捕獲到這個異常並進行處理。Java的異常處理是經過5個關鍵詞來實現的:try、catch、throw、throws和finally。通常狀況下是用try來執行一段程序,若是出現異常,系統會拋出(throws)一個異常,這時候你能夠經過它的類型來捕捉(catch)它,或最後(finally)由缺省處理器來處理。
用try來指定一塊預防全部"異常"的程序。緊跟在try程序後面,應包含一個catch子句來指定你想要捕捉的"異常"的類型。
throw語句用來明確地拋出一個"異常"。
throws用來標明一個成員函數可能拋出的各類"異常"。
Finally爲確保一段代碼無論發生什麼"異常"都被執行一段代碼。
能夠在一個成員函數調用的外面寫一個try語句,在這個成員函數內部寫另外一個try語句保護其餘代碼。每當遇到一個try語句,"異常"的框架就放到堆棧上面,直到全部的try語句都完成。若是下一級的try語句沒有對某種"異常"進行處理,堆棧就會展開,直到遇到有處理這種"異常"的try語句。
1. 經常使用的日誌框架
①Java Logging API(Oracle)—— Java默認的日誌框架
②Log4j(Apache)——開源日誌框架
③Logback(Logback Project)——開源項目,被設計成Log4j版本1的後續版本
④tinylog(tinylog)——輕量級開源logger
log4j定義了8個級別的log(除去OFF和ALL,能夠說分爲6個級別),優先級從高到低依次爲:OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL。
ALL 最低等級的,用於打開全部日誌記錄。
TRACE designates finer-grained informational events than the DEBUG.Since:1.2.12,很低的日誌級別,通常不會使用。
DEBUG 指出細粒度信息事件對調試應用程序是很是有幫助的,主要用於開發過程當中打印一些運行信息。
INFO 消息在粗粒度級別上突出強調應用程序的運行過程。打印一些你感興趣的或者重要的信息,這個能夠用於生產環境中輸出程序運行的一些重要信息,可是不能濫用,避免打印過多的日誌。
WARN 代表會出現潛在錯誤的情形,有些信息不是錯誤信息,可是也要給程序員的一些提示。
ERROR 指出雖然發生錯誤事件,但仍然不影響系統的繼續運行。打印錯誤和異常信息,若是不想輸出太多的日誌,能夠使用這個級別。
FATAL 指出每一個嚴重的錯誤事件將會致使應用程序的退出。這個級別比較高了。重大錯誤,這種級別你能夠直接中止程序了。
OFF 最高等級的,用於關閉全部日誌記錄。
反射是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲 Java 語言的反射機制。
JDBC中,利用反射動態加載了數據庫驅動程序。
Web服務器中利用反射調用了Sevlet的服務方法。
Eclispe等開發工具利用反射動態刨析對象的類型與結構,動態提示對象的屬性和方法。
不少框架都用到反射機制,注入屬性,調用方法,如Spring。
優勢:能夠動態執行,在運行期間根據業務功能動態執行方法、訪問屬性,最大限度發揮了java的靈活性。
缺點:對性能有影響,這類操做老是慢於直接執行java代碼。
動態代理是運行時動態生成代理類。
動態代理的應用有 Spring AOP數據查詢、測試框架的後端 mock、rpc,Java註解對象獲取等。
JDK 原生動態代理(發射機制)和 cglib 動態代理。
JDK 原生動態代理是基於接口實現的,而 cglib 是基於繼承當前類的子類實現的。
在運行時判斷任意一個對象所屬的類
在運行時構造任意一個類的對象
在運行時判斷任意一個類所具備的成員變量和方法
在運行時調用任意一個對象的方法
答:
- 方法1:類型.class,例如:String.class
- 方法2:對象.getClass(),例如:"hello".getClass()
- 方法3:Class.forName(),例如:Class.forName("java.lang.String")
答:
- 方法1:經過類對象調用newInstance()方法,例如:String.class.newInstance()
- 方法2:經過類對象的getConstructor()或getDeclaredConstructor()方法得到構造器(Constructor)對象並調用其newInstance()方法建立對象,例如:String.class.getConstructor(String.class).newInstance("Hello");
答:能夠經過類對象的getDeclaredField()方法字段(Field)對象,而後再經過字段對象的setAccessible(true)將其設置爲能夠訪問,接下來就能夠經過get/set方法來獲取/設置字段的值了。
數組是一種數據類型,即引用類型。數組是相同數據類型元素的集合。數組長度固定。
集合用來存放一組相同類型的對象,長度可變。
Array能夠包含基本類型和對象類型,ArrayList只能包含對象類型。
Array大小是固定的,ArrayList的大小是動態變化的。
ArrayList提供了更多的方法和特性,好比:addAll(),removeAll(),iterator()等等。
對於基本類型數據,集合使用自動裝箱來減小編碼工做量。可是,當處理固定大小的基本數據類型的時候,這種方式相對比較慢。
list、set能夠使用toArray()方法返回一個Obiect數組。數組轉list能夠使用Arrays.aslist()獲得一個list,再用list構造set(強轉)。
獲得key的集合,List<String> result = new ArrayList(map.keySet());
獲得values的集合,List<String> result2 = new ArrayList(map.values());
list轉map沒有意義,不是鍵值對。
Collection是集合類的上級接口,繼承與他的接口主要有Set 和List.
Collections是針對集合類的一個幫助類,他提供一系列靜態方法實現對各類集合的搜索、排序、線程安全化等操做
Set裏的元素是不能重複的,那麼用iterator()方法來區分重複與否。equals()是判讀兩個Set是否相等
equals()和==方法決定引用值是否指向同一對象equals()在類中被覆蓋,爲的是當兩個分離的對象的內容和類型相配的話,返回真值
List,Set是,Map不是,
Map是一個獨立的接口
AbstractMap<K,V> implements Map<K,V>
HashMap<K,V> extends AbstractMap<K,V>
就ArrayList與Vector主要從二方面來講.
一.同步性:Vector是線程安全的,也就是說是同步的,而ArrayList是線程序不安全的,不是同步的
二.數據增加:當須要增加時,Vector默認增加爲原來一培,而ArrayList倒是原來的一半
就HashMap與HashTable主要從三方面來講。
一.歷史緣由:Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現
二.同步性:Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的
三.值:只有HashMap的key或value能夠爲空值
Collection FrameWork以下:
Collection
├List 有序,可重複
│├LinkedList 底層數據結構是鏈表,查詢慢,增刪快,線程安全
│├ArrayList 底層數據結構是數組,查詢快,增刪慢,非線程安全
│└Vector 底層數據結構是數組,查詢快,增刪慢,線程安全
│ └Stack 棧類,先進後出
└Set 無序,惟一
│├HashSet 底層數據結構是哈希表,哈希表結合了數組的快速查詢的優勢又能融合鏈表方便快捷的增長刪除元素的優點。線程不安全,在HashSet中,底層源碼,其實就是一個HashMap,HashMap的key爲HashSet中的值,而value爲一個Object對象常量。
*哈希表依賴兩個方法hashcode()和equals(),首先判斷hasdcode()是否相同,是:繼續執行equals(),是true說明元素重複不添加,false添加到集合
│├LinkedHashSet 底層數據結構由哈希表和鏈表組成,由鏈表保證元素有序性,由哈希表保證元素惟一性。非線程安全
│├CopyOnWriteArraySet 底層數據結構是數組,CopyOnWriteArraySet是利用CopyOnWriteArrayList來實現的,由於CopyOnWriteArrayList是線程安全的,因此 CopyOnWriteArraySet操做也是線程安全的
Map
├Hashtable 底層數據結構是哈希表,線程安全的,效率低,不容許空值,無序
├HashMap 底層數據結構是哈希表,線程不安全,效率高,容許空值,無序
└linkedHashMap 底層數據由哈希表+鏈表組成,由鏈表保證元素有序,哈希保證元素惟一,非線程安全
arrayList初始長度是10,hashMap初始長度是16
Collection是最基本的集合接口,一個Collection表明一組Object,即Collection的元素(Elements)
Collections是集合的算法
ArrayList,Vector底層數據結構都是數組,查詢快,增刪慢。ArrayList線程不安全,Vector線程安全可是效率慢。LinkedList線程安全,底層數據結構是鏈表,查詢慢,增刪快。
HashMap和Hashtable底層數據結構都是哈希表。HashMap線程非安全,能夠容許空值,效率高。HashTable線程安全,效率低。
最經常使用的集合類是 List 和 Map。 List 的具體實現包括 ArrayList 和 Vector,它們是可變大小的列表,比較適合構建、存儲和操做任何類型對象的元素列表。 List 適用於按數值索引訪問元素的情形。
Map 提供了一個更通用的元素存儲方法。 Map 集合類用於存儲元素對(稱做"鍵"和"值"),其中每一個鍵映射到一個值。經過map.entrySet().iterator()或map.keySet().iterator()來獲取迭代器(iterator).hasNext()遍歷元素。
List 以特定次序來持有元素,可有重複元素。Set 沒法擁有重複元素,內部排序。Map 保存key-value值,value可多值。
由於ArrayList的底層是數組實現,而且數組的默認值是10,若是插入10000條要不斷的擴容,耗費時間,因此咱們調用ArrayList的指定容量的構造器方法ArrayList(int size) 就能夠實現不擴容,就提升了性能。
1:抽象類用abstract關鍵字,接口用interface
2:接口只能定義方法,抽象類不只能夠定義抽象方法,還能夠有實現方法
3:抽象類只能單一繼承,接口能夠被多重實現
抽象定義的類叫抽象類,抽象類字段默認friendly(本包可見),用abstract關鍵字定義抽象類和抽象方法。
4:抽象層次不一樣,抽象類是對類抽象,而接口是對行爲的抽象。
抽象方法沒有主體,有抽象方法的必定是抽象類。抽象類不必定必須有抽象方法,抽象類能夠定義和實現。抽象類只能被單一繼承extends。抽象類抽象方法不能使用private,由於不能被子類繼承。抽象方法不能使用static,由於方法沒有主體沒有意義。
接口(interface)是抽象類的變體。在接口中,全部方法都是抽象的。接口能夠被多重實現implements,接口的字段默認爲public static final。instanceof 運算符能夠用來決定某對象的類是否實現了接口
當存在繼承關係時用抽象類,只須要使用單一功能用接口。
*抽象類與接口都用於抽象,可是抽象類(JAVA中)能夠有本身的部分實現,而接口則徹底是一個標識(同時有多重繼承的功能)。
Collection框架中實現比較要實現Comparable 接口和 Comparator 接口,這兩個接口用於排序
都不能,abstract是沒有被實現的,而static必定要被實現的。Synchronized是須要同步的,abstract只有被子類繼承的時候才能添加同步。Native本地方法,它把具體的實現交給了本地的函數庫,沒有經過虛擬機,是java與其餘語言通訊的一種機制。與抽象方法把實現交給子類實現衝突。
接口能夠繼承接口。抽象類能夠實現(implements)接口,抽象類是否可繼承實體類,但前提是抽象類必須能訪問實體類的構造方法,子類默認調用父類的構造函數。若是實體了申明瞭一個private 的無參構造函數,則系統不會自動生成該類的無參構造函數,所以抽象類訪問不到實體類的構造函數而編譯失敗。
構造器Constructor不能被繼承,所以不能重寫Overriding,但能夠被重載Overloading(有參、無參、多參的構造函數)
Overloaded的方法是否能夠改變返回值的類型
方法的重寫Overriding和重載Overloading是Java多態性的不一樣表現。重寫Overriding是父類與子類之間多態性的一種表現,重載Overloading是一個類中多態性的一種表現。
子類重寫父類的方法,方法名、參數類型個數、返回值類型必須相同。子類的對象使用這個方法時,將調用子類中的定義,對它而言,父類中的定義如同被"屏蔽"了。發生在繼承類中,被重寫的方法不能有更高的權限。
若是在一個類中定義了多個同名的方法,方法名相同,參數類型或個數不一樣,返回值的類型也能夠不一樣。則稱爲方法的重載(Overloading)。發生在同一個類中,通常用於構造函數,對權限沒有要求。
匿名的內部類是沒有名字的內部類。不能extends(繼承) 其它類,但一個內部類能夠做爲一個接口,由另外一個內部類實現
因爲Java不支持多繼承,而有可能某個類或對象要使用分別在幾個類或對象裏面的方法或屬性,現有的單繼承機制就不能知足要求。與繼承相比,接口有更高的靈活性,由於接口中沒有任何實現代碼。當一個類實現了接口之後,該類要實現接口裏面全部的方法和屬性,而且接口裏面的屬性在默認狀態下面都是public static,全部方法默認狀況下是public.一個類能夠實現多個接口。
方法的重寫Overriding和重載Overloading是Java多態性的不一樣表現。重寫Overriding是父類與子類之間多態性的一種表現,重載Overloading是一個類中多態性的一種表現。
1發揮多核CPU的優點,相似與食堂多個窗口打飯
2防止阻塞,四車道與單車道的比較
3便於建模,能夠把前後順序關聯性不強的任務拆分紅幾個同步進行,提升效率。好比在生成一個汽車骨架的時候,相應的其餘零件也在同步生成,最後組裝。
一、繼承Thread類,重寫run方法
二、實現Runnable接口
三、經過Callable和FutureTack建立線程
四、經過線程池建立線程
知道前面兩種便可,相比實現Runnable接口更快捷,一Java支持單繼承,繼承Thread類就不能集成其餘類,繼承擴展性被佔,二線程可能只要求可執行便可,Thread類相比開銷過大。
簡而言之,進程是程序運行和資源分配的基本單位,一個程序至少有一個進程,一個進程至少有一個線程.進程在執行過程當中擁有獨立的內存單元,而多個線程共享內存資源,減小切換次數,從而效率更高.
線程是進程的一個實體,是cpu調度和分派的基本單位,是比程序更小的能獨立運行的基本單位.同一進程中的多個線程之間能夠併發執行.
程序運行完畢,jvm會等待非守護線程完成後關閉,可是jvm不會等待守護線程.守護線程最典型的例子就是GC線程
多線程的上下文切換是指CPU控制權由一個已經正在運行的線程切換到另一個就緒並等待獲取CPU執行權的線程的過程。
1)Sleeep來自Thread類,wait()來自Object類。
2)調用sleep()過程當中,線程不會釋放對象鎖,wait()方法會釋放。
3)sleep()睡眠後不讓出系統資源,wait()讓出資源
4)sleep(millssecond)須要指定一個睡眠時間,時間一到會自動喚醒
只有調用了start()方法,纔會表現出多線程的特性,不一樣線程的run()方法裏面的代碼交替執行。若是隻是調用run()方法,那麼代碼仍是同步執行的,必須等待一個線程的run()方法裏面的代碼所有執行完畢以後,另一個線程才能夠執行其run()方法裏面的代碼。
通俗的說:加鎖的就是是線程安全的,不加鎖的就是是線程不安全的
線程安全: 就是多線程訪問時,採用了加鎖機制,當一個線程訪問該類的某個數據時,進行保護,其餘線程不能進行訪問,直到該線程讀取完,其餘線程纔可以使用。不會出現數據不一致或者數據污染。
1)樂觀鎖:就像它的名字同樣,對於併發間操做產生的線程安全問題持樂觀狀態,樂觀鎖認爲競爭不老是會發生,所以它不須要持有鎖,將比較-替換這兩個動做做爲一個原子操做嘗試去修改內存中的變量,若是失敗則表示發生衝突,那麼就應該有相應的重試邏輯。
2)悲觀鎖:仍是像它的名字同樣,對於併發間操做產生的線程安全問題持悲觀狀態,悲觀鎖認爲競爭老是會發生,所以每次對某資源進行操做時,都會持有一個獨佔的鎖,就像synchronized,無論三七二十一,直接上了鎖就操做資源了。
CAS,全稱爲Compare and Swap,即比較-替換。假設有三個操做數:內存值V、舊的預期值A、要修改的值B,當且僅當預期值A和內存值V相同時,纔會將內存值修改成B並返回true,不然什麼都不作並返回false。
新建(New)、就緒(Runnable)、運行(Running)、阻塞(Blocked)和死亡(Dead)5種狀態。
*新建狀態,當程序使用new關鍵字建立了一個線程以後,該線程就處於新建狀態,此時僅由JVM爲其分配內存,並初始化其成員變量的值
*就緒狀態,當線程對象調用了start()方法以後,該線程處於就緒狀態。Java虛擬機會爲其建立方法調用棧和程序計數器,等待調度運行
*運行狀態,若是處於就緒狀態的線程得到了CPU,開始執行run()方法的線程執行體,則該線程處於運行狀態
*阻塞狀態,當處於運行狀態的線程失去所佔用資源以後,便進入阻塞狀態
*死亡狀態,線程在run()方法執行結束後進入死亡狀態。此外,若是線程執行了interrupt()或stop()方法,那麼它也會以異常退出的方式進入死亡狀態。
(1)線程睡眠:Thread.sleep (long millis)方法,使線程轉到阻塞狀態。millis參數設定睡眠的時間,以毫秒爲單位。當睡眠結束後,就轉爲就緒(Runnable)狀態。sleep()平臺移植性好。
(2)線程等待:Object類中的wait()方法,致使當前的線程等待,直到其餘線程調用此對象的 notify() 喚醒方法。這個兩個喚醒方法也是Object類中的方法,行爲等價於調用 wait() 同樣。wait() 和 notify() 方法:兩個方法配套使用,wait() 使得線程進入阻塞狀態,它有兩種形式,一種容許 指定以毫秒爲單位的一段時間做爲參數,另外一種沒有參數,前者當對應的 notify() 被調用或者超出指定時間時線程從新進入可執行狀態,後者則必須對應的 notify() 被調用.
(3)線程禮讓,Thread.yield() 方法,暫停當前正在執行的線程對象,把執行機會讓給相同或者更高優先級的線程。yield() 使得線程放棄當前分得的 CPU 時間,可是不使線程阻塞,即線程仍處於可執行狀態,隨時可能再次分得 CPU 時間。調用 yield() 的效果等價於調度程序認爲該線程已執行了足夠的時間從而轉到另外一個線程.
(4)線程自閉,join()方法,等待其餘線程終止。在當前線程中調用另外一個線程的join()方法,則當前線程轉入阻塞狀態,直到另外一個進程運行結束,當前線程再由阻塞轉爲就緒狀態。
死鎖是指兩個以上的進程在執行過程當中,因爲競爭資源或通訊形成的一種阻塞現象,若無外力做用,它們將沒法推行下去。
1.互斥條件:一個資源每次只能被一個進程使用。
2.請求與保持條件:一個進程因請求資源而阻塞時,對已得到的資源保持不放。
3.不剝奪條件:進程已得到的資源,在末使用完以前,不能強行剝奪。
4.循環等待條件:若干進程之間造成一種頭尾相接的循環等待資源關係。
一、不讓產生死鎖的四個條件同時成立
二、合理分配資源
三、使用銀行家算法,若是該進程請求的資源當前操做系統餘量能夠知足,就分配
(1)管道(Pipe):管道可用於具備親緣關係進程間的通訊,容許一個進程和另外一個與它有共同祖先的進程之間進行通訊。
(2)命名管道(named pipe):命名管道克服了管道沒有名字的限制,所以,除具備管道所具備的功能外,它還容許無親緣關 系 進程間的通訊。命名管道在文件系統中有對應的文件名。命名管道經過命令mkfifo或系統調用mkfifo來建立。
(3)信號(Signal):信號是比較複雜的通訊方式,用於通知接受進程有某種事件發生,除了用於進程間通訊外,進程還能夠發送 信號給進程自己;linux除了支持Unix早期信號語義函數sigal外,還支持語義符合Posix.1標準的信號函數sigaction(實際上,該函數是基於BSD的,BSD爲了實現可靠信號機制,又可以統一對外接口,用sigaction函數從新實現了signal函數)。
(4)消息(Message)隊列:消息隊列是消息的連接表,包括Posix消息隊列system V消息隊列。有足夠權限的進程能夠向隊列中添加消息,被賦予讀權限的進程則能夠讀走隊列中的消息。消息隊列克服了信號承載信息量少,管道只能承載無格式字節流以及緩衝區大小受限等缺
(5)共享內存:使得多個進程能夠訪問同一塊內存空間,是最快的可用IPC形式。是針對其餘通訊機制運行效率較低而設計的。每每與其它通訊機制,如信號量結合使用,來達到進程間的同步及互斥。
(6)內存映射(mapped memory):內存映射容許任何多個進程間通訊,每個使用該機制的進程經過把一個共享的文件映射到本身的進程地址空間來實現它。
(7)信號量(semaphore):主要做爲進程間以及同一進程不一樣線程之間的同步手段。
(8)套接口(Socket):更爲通常的進程間通訊機制,可用於不一樣機器之間的進程間通訊。起初是由Unix系統的BSD分支開發出來的,但如今通常能夠移植到其它類Unix系統上:Linux和System V的變種都支持套接字。
1)自旋鎖:自旋鎖顧名思義,它會等待必定時間(自旋),在這期中會什麼都不作就是等資源被釋放,好處在於沒有了內核態用戶態切換的效率損失,可是若是它一直不能訪問到資源的話就會一直佔用cpu資源,因此它會循環一段時間後進入阻塞狀態。
重量級鎖:synchronized就是重量級鎖的實現機制,搶不到資源的進程會進入阻塞狀態
2)偏向鎖:顧名思義,它會偏向第一個訪問資源的進程,若是說只有一個進程執行同步代碼塊,那麼就會上個偏向鎖,若是有其餘線程搶佔資源,那麼就會升級爲輕量級鎖
輕量級鎖:偏向鎖升級以後就是輕量級鎖,鎖只能夠升級而不能夠降級。輕量級鎖中的其餘進程會進入自選狀態,若是說自選失敗,就會升級會重量級鎖
3)公平,非公平鎖:主要是指線程是否先來後到拿到鎖,synchronized是非公平的,而ReentrantLock默認非公平,能夠設置爲公平鎖
4)悲觀鎖:老是假設最壞的狀況,每次去拿數據的時候都認爲別人會修改,因此每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會阻塞直到它拿到鎖(共享資源每次只給一個線程使用,其它線程阻塞,用完後再把資源轉讓給其它線程)。傳統的關係型數據庫裏邊就用到了不少這種鎖機制,好比行鎖,表鎖等,讀鎖,寫鎖等,都是在作操做以前先上鎖。Java中synchronized和ReentrantLock等獨佔鎖就是悲觀鎖思想的實現。
5)樂觀鎖:老是假設最好的狀況,每次去拿數據的時候都認爲別人不會修改,因此不會上鎖,可是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,能夠使用版本號機制(數據庫中)和CAS算法實現
1)sleep()給其它線程運行機會不會考慮線程優先級,yield()只會給相同優先級或更高優先級的線程機會
2)線程執行sleep()方法後進入阻塞狀態,而執行yeild()進入就緒狀態
3)sleep()方法須要拋出異常interupdateException,而yeild()不用拋異常
4)sleep()比yield()有更好的移植性
線程. setPriority()方法來設置線程的優先級,參數是1~10,默認是5。優先級和線程搶到資源的機率沒有關係。結合yeild()就有用了。
一、吞吐量:你作WEB,容器幫你作了多線程,可是他只能幫你作請求層面的。簡單的說,可能就是一個請求一個線程。或多個請求一個線程。若是是單線程,那同時只能處理一個用戶的請求。
二、伸縮性:也就是說,你能夠經過增長CPU核數來提高性能。若是是單線程,那程序執行到死也就利用了單核,確定沒辦法經過增長CPU核數來提高性能。鑑於你是作WEB的,第1點可能你幾乎不涉及。那這裏我就講第二點吧。--舉個簡單的例子:假設有個請求,這個請求服務端的處理須要執行3個很緩慢的IO操做(好比數據庫查詢或文件查詢),那麼正常的順序多是(括號裏面表明執行時間):
a、讀取文件1 (10ms)
b、處理1的數據(1ms)
c、讀取文件2 (10ms)
d、處理2的數據(1ms)
e、讀取文件3 (10ms)
f、處理3的數據(1ms)
若是作 java web 方面開發的話幾乎用不到多線程!由於有多線程的地方 servlet 容器或者其餘開發框架都已經實現掉了!
通常在網絡應用程序中使用多線程的地方很是多!
另外,你說的拷貝文件使用多線程,那是沒有用的!以多線程來提升效率的場景通常在 CPU 計算型,而不是在 IO 讀寫型。CPU 能夠會有多個核心並行處理計算,可是磁盤 IO 就沒這功能了,磁頭只有一個,根本不可能靠多線程提升效率!
通常來講,磁盤 IO 的併發能力爲 0,也就是說沒法支持併發!網絡 IO 的話因爲帶寬的限制的,使用多線程處理最多也只能達到帶寬的極值。
對於磁盤 IO 來講,多線程能夠用於一個線程專門用於讀寫文件,其餘的線程用於對讀取數據進行處理,這樣纔有可能更好地利用 CPU 資源。
若是僅僅是單純的文件複製,使用多線程操做的話,會使用磁頭在磁盤上不停地進行尋道操做,使得效率更爲低下!
1.建立+執行+銷燬線程>單線程時間
2.一個線程默認佔用1M,內存銷燬
3.頻繁切換線程上下文影響性能
若是異常沒有被捕獲該線程將會中止執行。Thread.UncaughtExceptionHandler 是用於處理未捕獲異常形成線程忽然中斷狀況的一個內嵌接口。當一個未捕獲異常將形成線程中斷的時候JVM會使用Thread.getUncaughtExceptionHandler()來查詢線程的UncaughtExceptionHandler並將線程和異常做爲參數傳遞給handler的uncaughtException()方法進行處理。
鎖類、鎖方法、鎖代碼塊。
線程過多會形成棧溢出,也有可能會形成堆異常。
Java 中平時用的最多的 Map 集合就是 HashMap 了,它是線程不安全的
看下面兩個場景:
一、當用在方法內的局部變量時,局部變量屬於當前線程級別的變量,其餘線程訪問
不了,因此這時也不存在線程安全不安全的問題了。
二、當用在單例對象成員變量的時候呢?這時候多個線程過來訪問的就是同一個
HashMap 了,對同個 HashMap 操做這時候就存在線程安全的問題了。
java.lang.Thread#holdsLock 方法
3二、線程同步須要注意什麼?
一、儘可能縮小同步的範圍,增長系統吞吐量。
二、分佈式同步鎖無心義,要使用分佈式鎖。
三、防止死鎖,注意加鎖順序。
3五、線程之間如何傳遞數據?
通 過 在 線 程 之 間 共 享 對 象 就 可 以 了 , 然 後 通 過 wait/notify/notifyAll 、
await/signal/signalAll 進行喚起和等待,比方說阻塞隊列 BlockingQueue 就是爲線程之
間共享數據而設計的
1)工廠模式:有一個專門的類負責建立實例的過程。
2)單例模式:一個類始終只能建立一個實例。
3)代理模式:一個對象表明另外一個對象採起行動。是一種很是普遍的設計模式,例如hibernate中A對象管理B對象,加載A對象的時候先加載一個B的代理對象,只有在實際使用到B對象的時候纔會加載B的實體。
4)觀察模式:觀察者模式定義了一對多關聯依賴關係,讓一個或多個對象觀察一個主題對象。當主題對象發生變化時,系統通知全部的觀察者對象自動更新。
懶漢模式:在類加載的時候不被初始化。
餓漢模式:在類加載時就完成了初始化,可是加載比較慢,獲取對象比較快。
餓漢模式是線程安全的,在類建立好一個靜態對象提供給系統使用,懶漢模式在建立對象時不加上synchronized,會致使對象的訪問不是線程安全的
高內聚低耦合是軟件設計的一個基本原則,說的是在程序的各個模塊中,儘可能讓每一個模塊獨立,相關的處理儘可能在單個模塊中完成。優勢:能提下降各模塊的之間的聯繫,減小「牽一髮而動全身」的概率,提升開發效率,下降升級維護成本,也便於進行單元測試,提升軟件質量。
1)單一職責原則:一個類值負責一個功能的職責
2)開閉原則:擴展開放,修改關閉。
3)里氏代換原則:使用父類的地方都能使用子類對象
4)依賴倒轉原則:針對接口編程,
5)接口隔離原則:針對不一樣部分用專門接口,不用總接口,須要哪些接口就用哪些接口
6)迪米特法則: 軟件實體類,儘可能不與其餘實體類發生關係相互做用,對外都統一的暴露接口就好了
許多的設計模式,包括一些框架,都是參考高內聚低耦合這個點的。
答:首先 Java 的 IO 庫提供了一種連接(Chaining)機制,能夠將一個流處理器跟另外一個流處理器首尾相接,以其中之一的輸出做爲另外一個的輸入而造成一個流管道連接,譬如常見的 new DataInputStream(new FileInputStream(file)) 就是把 FileInputStream 流看成 DataInputStream 流的管道連接。
其次,對於 Java IO 流還涉及一種對稱性的設計策略,其表現爲輸入輸出對稱性(如 InputStream 和 OutputStream 的字節輸入輸出操做,Reader 和 Writer 的字符輸入輸出操做)和字節字符的對稱性(InputStream 和 Reader 的字節字符輸入操做,OutputStream 和 Writer 的字節字符輸出操做)。
此外,對於 Java IO 流在總體設計上還涉及裝飾者(Decorator)和適配器(Adapter)兩種設計模式。
對於 IO 流涉及的裝飾者設計模式例子以下:
//把InputStreamReader裝飾成BufferedReader來成爲具有緩衝能力的Reader。
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
對於 IO 流涉及的適配器設計模式例子以下:
//把FileInputStream文件字節流適配成InputStreamReader字符流來操做文件字符串。
FileInputStream fileInput = new FileInputStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(fileInput);
而對於上面涉及的兩種設計模式通俗總結以下。
裝飾者模式就是給一個對象增長一些新的功能,並且是動態的,要求裝飾對象和被裝飾對象實現同一個接口,裝飾對象持有被裝飾對象的實例(各類字符流間裝飾,各類字節流間裝飾)。
適配器模式就是將某個類的接口轉換成咱們指望的另外一個接口表示,目的是消除因爲接口不匹配所形成的類的兼容性問題(字符流與字節流間互相適配)。
答:計算機中的一切最終都是以二進制字節形式存在的,對於咱們常常操做的字符串,在寫入時其實都是先獲得了其對應的字節,而後將字節寫入到輸出流,在讀取時其實都是先讀到的是字節,而後將字節直接使用或者轉換爲字符給咱們使用。因爲對於字節和字符兩種操做的需求比較普遍,因此 Java 專門提供了字符流與字節流相關IO類。
對於程序運行的底層設備來講永遠都只接受字節數據,因此當咱們往設備寫數據時不管是字節仍是字符最終都是寫的字節流。字符流是字節流的包裝類,因此當咱們將字符流向字節流轉換時要注意編碼問題(由於字符串轉成字節數組的實質是轉成該字符串的某種字節編碼)。
字符流和字節流的使用很是類似,可是實際上字節流的操做不會通過緩衝區(內存)而是直接操做文本自己的,而字符流的操做會先通過緩衝區(內存)而後經過緩衝區再操做文件。
答:緩衝區就是一段特殊的內存區域,不少狀況下當程序須要頻繁地操做一個資源(如文件或數據庫)則性能會很低,因此爲了提高性能就能夠將一部分數據暫時讀寫到緩存區,之後直接今後區域中讀寫數據便可,這樣就顯著提高了性能。
對於 Java 字符流的操做都是在緩衝區操做的,因此若是咱們想在字符流操做中主動將緩衝區刷新到文件則能夠使用 flush() 方法操做。
答:大多數狀況下使用字節流會更好,而大多數時候 IO 操做都是直接操做磁盤文件,因此這些流在傳輸時都是以字節的方式進行的(圖片等都是按字節存儲的)。
而若是對於操做須要經過 IO 在內存中頻繁處理字符串的狀況使用字符流會好些,由於字符流具有緩衝區,提升了性能。
字節流,字符流。字節流繼承於InputStream OutputStream,字符流繼承於InputStreamReader OutputStreamWriter。在java.io包中還有許多其餘的流,主要是爲了提升性能和使用方便。
計算機中的底層一切最終都是二進制的字節形式存在。首先讀取的是字節,而後用字符流讀取字符,字符流只能處理字符或者字符串。字節流通常用於傳輸,字符用於讀取字符。字節流能夠用於任何類型的對象,包括二進制,但它不能直接處理unicode字符,字符流能夠。
*序列化:把Java對象轉換爲字節序列的過程。
*反序列化:把字節序列恢復爲Java對象的過程。
序列化就是一種用來處理對象流的機制,把對象轉換成字節流方便網絡傳輸。
序列化的實現:將須要被序列化的類實現Serializable接口,該接口沒有須要實現的方法。implements Serializable只是爲了標註該對象是可被序列化的,而後使用一個輸出流(如:FileOutputStream)來構造一個ObjectOutputStream(對象流)對象,接着,使用ObjectOutputStream對象的writeObject(Object obj)方法就能夠將參數爲obj的對象寫出(即保存其狀態),要恢復的話則用輸入流。
泛型,即「參數化類型」。建立集合時就指定集合元素的類型,該集合只能保存其指定類型的元素,避免使用強制類型轉換。
Java編譯器生成的字節碼是不包涵泛型信息的,泛型類型信息將在編譯處理是被擦除,這個過程即類型擦除。泛型擦除能夠簡單的理解爲將泛型java代碼轉換爲普通java代碼,只不過編譯器更直接點,將泛型java代碼直接轉換成普通java字節碼。
類型擦除的主要過程以下:
1).將全部的泛型參數用其最左邊界(最頂級的父類型)類型替換。
2).移除全部的類型參數。
泛型是經過類型擦除來實現的,編譯器在編譯時擦除了全部類型相關的信息,因此在運行時不存在任何類型相關的信息。例如List<String>在運行時僅用一個List來表示。這樣作的目的,是確保能和Java 5以前的版本開發二進制類庫進行兼容。你沒法在運行時訪問到類型參數,由於編譯器已經把泛型類型轉換成了原始類型。根據你對這個泛型問題的回答狀況,你會獲得一些後續提問,好比爲何泛型是由類型擦除來實現的或者給你展現一些會致使編譯器出錯的錯誤泛型代碼。請閱讀個人Java中泛型是如何工做的來了解更多信息。
限定通配符對類型進行了限制。有兩種限定通配符,一種是<? extends T>它經過確保類型必須是T的子類來設定類型的上界,另外一種是<? super T>它經過確保類型必須是T的父類來設定類型的下界。泛型類型必須用限定內的類型來進行初始化,不然會致使編譯錯誤。另外一方面<?>表示了非限定通配符,由於<?>能夠用任意類型來替代。更多信息請參閱個人文章泛型中限定通配符和非限定通配符之間的區別。
這兩個List的聲明都是限定通配符的例子,List<? extends T>能夠接受任何繼承自T的類型的List,而List<? super T>能夠接受任何T的父類構成的List。例如List<? extends Number>能夠接受List<Integer>或List<Float>。在本段出現的鏈接中能夠找到更多信息。
編寫泛型方法並不困難,你須要用泛型類型來替代原始類型,好比使用T, E or K,V等被普遍承認的類型佔位符。泛型方法的例子請參閱Java集合類框架。最簡單的狀況下,一個泛型方法可能會像這樣:
public V put(K key, V value) {
return cache.put(key, value);
}
這樣作的話會致使編譯錯誤。由於List<Object>能夠存儲任何類型的對象包括String, Integer等等,而List<String>卻只能用來存儲Strings。
List<Object> objectList;
List<String> stringList;
objectList = stringList;
Array不支持泛型,這也是List代替Array的一個緣由,由於List能夠提供編譯期的類型安全保證,而Array卻不能。
若是你把泛型和原始類型混合起來使用,例以下列代碼,Java 5的javac編譯器會產生類型未檢查的警告,例如
List<String> rawList = new ArrayList()
排序的方法有:插入排序(直接插入排序、希爾排序),交換排序(冒泡排序、快速排序),選擇排序(直接選擇排序、堆排序),歸併排序,分配排序(箱排序、基數排序)
快速排序是一種經常使用的排序算法,比冒泡排序快不少。
**在快速排序中使用了大量的遞歸,快速排序的三個步驟:
一、選擇基準值
二、將數組分紅兩個子數組;小於基準值的元素和大於基準值的元素
三、對這兩個子數組進行快速排序(遞歸)
快速排序的速度取決於選擇的基準值,運行速度記作 O(n longn ),大O表示法底數默認爲2
**選擇排序的數組位移在外層循環,而冒泡排序的位移在內循環。
最慢的算法,有一個旅行商要到N個城市去旅遊,但願計算出最短的路線。計算公式爲n!=1×2×3×...×n。也就是n的階乘。
區別:
xml是重量級、json是輕量級
xml比較佔帶寬、json佔帶寬小,易於壓縮
json在webservice 用的比較少、xml用的較多
相同:
二者都用在項目交互下 例如 移動app接口用的就是json、在web項目中與其餘項目對接用xml較多。
json經常使用解析方法 gson、jsonobject、jackson等 xml dom sax pull 解析
DAO模式的組成部分:
1.DAO接口
2.DAO實現類
3.實體類
4.數據庫鏈接和關閉工具類
DAO模式的做用:
1.隔離業務邏輯代碼和數據訪問代碼
2.隔離不一樣數據庫的實現
Spring MVC是一個基於Java的實現了MVC設計模式的請求驅動類型的輕量級Web框架,經過把Model,View,Controller分離,將web層進行職責解耦,把複雜的web應用分紅邏輯清晰的幾部分,簡化開發,減小出錯,方便組內開發人員之間的配合。
輕量級是指代碼的侵入性,能夠理解爲框架與業務代碼的耦合程度。SpringMVC是經過註解或外部文件進行配置的,不須要繼承框架裏的類或顯示調用框架裏的類或方法,所以是輕量級的。
(1)用戶發送請求至前端控制器DispatcherServlet;
(2) DispatcherServlet收到請求後,調用HandlerMapping處理器映射器,查找匹配該url 的handle,並返回一個執行鏈,沒有則返回404
(3)DispatcherServlet 調用 HandlerAdapter處理器適配器返回ModelAndView;
(4)DispatcherServlet將ModelAndView傳給ViewResolver視圖解析器進行解析並返回視圖View;
(5)DispatcherServlet對View進行渲染視圖(即將模型數據填充至視圖中),並把數據裝入到request域,返回給用戶
(1)能夠支持各類視圖技術,而不只僅侷限於JSP;
(2)與Spring框架集成(如IoC容器、AOP等);
(3)清晰的角色分配:前端控制器(dispatcherServlet) , 請求處處理器映射(handlerMapping), 處理器適配器(HandlerAdapter), 視圖解析器(ViewResolver)。
(4) 支持各類請求資源的映射策略。
(1)前端控制器 DispatcherServlet(不須要程序員開發)
做用:接收請求、響應結果,至關於轉發器,有了DispatcherServlet 就減小了其它組件之間的耦合度。
(2)處理器映射器HandlerMapping(不須要程序員開發)
做用:根據請求的URL來查找Handler
(3)處理器適配器HandlerAdapter
注意:在編寫Handler的時候要按照HandlerAdapter要求的規則去編寫,這樣適配器HandlerAdapter才能夠正確的去執行Handler。
(4)處理器Handler(須要程序員開發)
(5)視圖解析器 ViewResolver(不須要程序員開發)
做用:進行視圖的解析,根據視圖邏輯名解析成真正的視圖(view)
(6)視圖View(須要程序員開發jsp)
View是一個接口, 它的實現類支持不一樣的視圖類型(jsp,freemarker,pdf等等)
(1)springmvc的入口是一個servlet即前端控制器(DispatchServlet),而struts2入口是一個filter過慮器(StrutsPrepareAndExecuteFilter)。
(2)springmvc是基於方法開發(一個url對應一個方法),請求參數傳遞到方法的形參,能夠設計爲單例或多例(建議單例),struts2是基於類開發,傳遞參數是經過類的屬性,只能設計爲多例。
(3)Struts採用值棧存儲請求和響應的數據,經過OGNL存取數據,springmvc經過參數解析器是將request請求內容解析,並給方法形參賦值,將數據和視圖封裝成ModelAndView對象,最後又將ModelAndView中的模型數據經過reques域傳輸到頁面。Jsp視圖解析器默認使用jstl。
(1)轉發:在返回值前面加"forward:",譬如"forward:user.do?name=method4"
(2)重定向:在返回值前面加"redirect:",譬如"redirect:http://www.baidu.com"
七、SpringMvc怎麼和AJAX相互調用的?
經過Jackson框架就能夠把Java裏面的對象直接轉化成Js能夠識別的Json對象。具體步驟以下 :
(1)加入Jackson.jar
(2)在配置文件中配置json的映射
(3)在接受Ajax方法裏面能夠直接返回Object,List等,但方法前面要加上@ResponseBody註解。
(1)解決post請求亂碼問題:
在web.xml中配置一個CharacterEncodingFilter過濾器,設置成utf-8;
(2)get請求中文參數出現亂碼解決方法有兩個:
①修改tomcat配置文件添加編碼與工程編碼一致,以下:
<ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
②另一種方法對參數進行從新編碼:
String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")
ISO8859-1是tomcat默認編碼,須要將tomcat編碼後的內容按utf-8編碼。
答:能夠將異常拋給Spring框架,由Spring框架來處理;咱們只須要配置簡單的異常處理器,在異常處理器中添視圖頁面便可。
答:是單例模式,因此在多線程訪問的時候有線程安全問題,不要用同步,會影響性能的,解決方案是在控制器裏面不能寫字段。
@RequestMapping:用於處理請求 url 映射的註解,可用於類或方法上。用於類上,則表示類中的全部響應請求的方法都是以該地址做爲父路徑。
@RequestBody:註解實現接收http請求的json數據,將json轉換爲java對象。
@ResponseBody:註解實現將conreoller方法返回對象轉化爲json對象響應給客戶。
答:通常用@Controller註解,也能夠使用@RestController,@RestController註解至關於@ResponseBody + @Controller,表示是表現層,除此以外,通常不用別的註解代替。
答:能夠在@RequestMapping註解裏面加上method=RequestMethod.GET。
答:直接在方法的形參中聲明request,SpringMvc就自動把request對象傳入。
答:直接在形參裏面聲明這個參數就能夠,但必須名字和傳過來的參數同樣。
答:直接在方法中聲明這個對象,SpringMvc就自動會把屬性賦值到這個對象裏面。
答:返回值能夠有不少類型,有String, ModelAndView。ModelAndView類把視圖和數據都合併的一塊兒的,但通常用String比較好。
答:經過ModelMap對象,能夠在這個對象裏面調用put方法,把對象加到裏面,前臺就能夠經過el表達式拿到。
答:能夠在類上面加上@SessionAttributes註解,裏面包含的字符串就是要放入session裏面的key。
有兩種寫法,一種是實現HandlerInterceptor接口,另一種是繼承適配器類,接着在接口方法當中,實現處理邏輯;而後在SpringMvc的配置文件中配置攔截器便可:
<!-- 配置SpringMvc的攔截器 -->
<mvc:interceptors>
<!-- 配置一個攔截器的Bean就能夠了 默認是對全部請求都攔截 -->
<bean id="myInterceptor" class="com.zwp.action.MyHandlerInterceptor"></bean>
<!-- 只針對部分請求攔截 -->
<mvc:interceptor>
<mvc:mapping path="/modelMap.do" />
<bean class="com.zwp.action.MyHandlerInterceptorAdapter" />
</mvc:interceptor>
</mvc:interceptors>
註解本質是一個繼承了Annotation的特殊接口,其具體實現類是Java運行時生成的動態代理類。咱們經過反射獲取註解時,返回的是Java運行時生成的動態代理對象。經過代理對象調用自定義註解的方法,會最終調用AnnotationInvocationHandler的invoke方法。該方法會從memberValues這個Map中索引出對應的值。而memberValues的來源是Java常量池。
Struts 2框架自己大體能夠分爲3個部分:核心控制器FilterDispatcher、業務控制器Action和用戶實現的企業業務邏輯組件。 1)核心控制器FilterDispatcher是Struts 2框架的基礎,包含了框架內部的控制流程和處理機制。
2)業務控制器Action和業務邏輯組件是須要用戶來本身實現的。用戶在開發Action和業務邏輯組件的同時,還須要編寫相關的配置文件,供核心控制器FilterDispatcher來使用。
Struts 2的工做流程相對於Struts 1要簡單,與WebWork框架基本相同,因此說Struts 2是WebWork的升級版本。
基本簡要流程以下:
1)客戶端瀏覽器發出HTTP請求。
2)根據web.xml配置,該請求被FilterDispatcher接收。
3)根據struts.xml配置,找到須要調用的Action類和方法, 並經過IoC方式,將值注入給Aciton。
4)Action調用業務邏輯組件處理業務邏輯,這一步包含表單驗證。
5)Action執行完畢,根據struts.xml中的配置找到對應的返回結果result,並跳轉到相應頁面。
6)返回HTTP響應到客戶端瀏覽器。
1)攔截器是struts2核心組成部分,它提供了一種機制,使得開發者能夠定義一個特定的功能模塊,這個模塊會在Action執行以前或者以後執行,也能夠在Action執行以前阻止Action執行。
2)經常使用的攔截器有:
chain:在不一樣請求之間將請求參數在不一樣名字件轉換,請求內容不變
fileUpload:提供文件上傳。
i18n:記錄用戶選擇的區域環境
logger:輸出Action的名字
params:將請求中的參數設置到Action中去。
1)在軟件設計上Struts2的應用能夠不依賴於Servlet API和struts API。 Struts2的這種設計屬於無侵入式設計;
2)攔截器,實現如參數攔截注入等功能;
3)類型轉換器,能夠把特殊的請求參數轉換成須要的類型;
4)多種表現層技術,如:JSP、freeMarker、Velocity等;
5)Struts2的輸入校驗能夠對指定某個方法進行校驗;
6)提供了全局範圍、包範圍和Action範圍的國際化資源文件管理實現
7) 實現MVC模式,結構清晰,使開發者只關注業務邏輯的實現。有豐富的tag能夠用,大大提升了開發效率。(簡要)
OGNL是Object-Graph Navigation Language的縮寫,也叫對象導航語言。它是Struts的一種功能強大的表達式語言列如:訪問session中的user對象的username屬性:注意的是:使用前須要在頁面頭部導入taglib prefix="s" uri="/struts-tags"
14六、什麼是國際化,struts2實現國際化的原理?
國際化是根據不一樣的國家和地區的語言文化的不一樣,所設計的適用於不一樣地區的編碼格式。
實現方法:
1)首先在src目錄下新建message_en.properties(英文);
2)頁面獲取國際化信息或者使用
原理:程序獲得當前運行環境的國際/區域,語言環境並存放於Locale,ResourceBundle根據Locale中信息自動搜索對應的國際化資源文件並加載。
Ajax又叫異步刷新,(JavaScript和xml)原理:使用HttpRequest向服務器發送異步請求,服務器返回處理結果
反射,程序運行時動態獲取類型信息,完成對象建立,方法調用等。
例如:
Class myclass=Class.forNama("包名.類名");
Student stu=Factory.createInstance("stu1");
在struts.xml中配置type="redirect"(重定向);type="redirectAction"(轉發)
dispatcher:result type默認的類型,至關於servlet的foward方式跳轉頁面。客戶端看到的是struts2中配置的地址,而不是真正頁面的地址,通常用於跳轉到jsp頁面,頁面能拿到值
redirect:頁面重定向,客戶端跳轉,數據所有丟失,地址欄發生變化,頁面不能拿到值
chain:將請求轉發給一個Action,Action能經過getAttribute(「uname」)拿到值
redirect-action:通常用於跳轉到Action,Action不能經過getAttribute(「uname」)拿到值十、struts2默認能解決get和post提交方式的亂碼問題嗎?
答:不能。struts.i18n.encoding=UTF-8屬性值只能解析POST提交下的亂碼問題。
MVC模式:
1)web應用程序啓動時就會加載並初始化ActionServler。
2)用戶提交表單時,一個配置好的ActionForm對象被建立,並被填入表單相應的數據,ActionServler根據Struts-config.xml文件配置好的設置決定是否須要表單驗證,若是須要就調用ActionForm的Validate()驗證後選擇將請求發送到哪一個Action,若是Action不存在,ActionServlet會先建立這個對象,而後調用Action的execute()方法.
3)Execute()從ActionForm對象中獲取數據,完成業務邏輯,返回一個ActionForward對象,ActionServlet再把客戶請求轉發給ActionForward對象指定的jsp組件,ActionForward對象指定的jsp生成動態的網頁,返回給客戶。
1)攔截器是基於java反射機制的,而過濾器是基於函數回調的。
2)過濾器依賴於servlet容器,而攔截器不依賴於servlet容器。
3)攔截器只能對Action請求起做用,而過濾器則能夠對幾乎全部請求起做用。
4)攔截器能夠訪問Action上下文、值棧裏的對象,而過濾器不能。
5)在Action的生命週期中,攔截器能夠屢次調用,而過濾器只能在容器初始化時被調用一次。
fileUpload 提供文件上傳功能
i18n 記錄用戶選擇的locale
cookies 使用配置的name,value來是指cookies
checkbox 添加了checkbox自動處理代碼,將沒有選中的checkbox的內容設定爲false,而html默認狀況下不提交沒有選中的 checkbox。
chain 讓前一個Action的屬性能夠被後一個Action訪問,如今和chain類型的result()結合使用。
alias 在不一樣請求之間將請求參數在不一樣名字件轉換,請求內容不變
1)ActionContext是當前的Action的上下文環境,經過ActionContext能夠獲取到request、session、ServletContext等與Action有關的對象的引用;
2)ServletContext是域對象,一個web應用中只有一個ServletContext,生命週期伴隨整個web應用;
3)pageContext是JSP中的最重要的一個內置對象,能夠經過pageContext獲取其餘域對象的應用,同時它是一個域對象,做用範圍只針對當前頁面,當前頁面結束時,pageContext銷燬, 生命週期是JSP四個域對象中最小的。
1)每一個攔截器都是實現了Interceptor接口的 Java 類;
2)init(): 該方法將在攔截器被建立後當即被調用, 它在攔截器的生命週期內只被調用一次. 能夠在該方法中對相關資源進行必要的初始化;
3)intercept(ActionInvocation invocation): 每攔截一個動做請求, 該方法就會被調用一次;
4)destroy: 該方法將在攔截器被銷燬以前被調用, 它在攔截器的生命週期內也只被調用一次;
5)struts2中有內置了18個攔截器。
(1)Mybatis是一個半ORM(對象關係映射)框架,它內部封裝了JDBC,開發時只須要關注SQL語句自己,不須要花費精力去處理加載驅動、建立鏈接、建立statement等繁雜的過程。程序員直接編寫原生態sql,能夠嚴格控制sql執行性能,靈活度高。
(2)MyBatis 能夠使用 XML 或註解來配置和映射原生信息,將 POJO映射成數據庫中的記錄,避免了幾乎全部的 JDBC 代碼和手動設置參數以及獲取結果集。
(3)經過xml 文件或註解的方式將要執行的各類 statement 配置起來,並經過java對象和 statement中sql的動態參數進行映射生成最終執行的sql語句,最後由mybatis框架執行sql並將結果映射爲java對象並返回。(從執行sql到返回result的過程)。
(1)基於SQL語句編程,至關靈活,不會對應用程序或者數據庫的現有設計形成任何影響,SQL寫在XML裏,解除sql與程序代碼的耦合,便於統一管理;提供XML標籤,支持編寫動態SQL語句,並可重用。
(2)與JDBC相比,減小了50%以上的代碼量,消除了JDBC大量冗餘的代碼,不須要手動開關鏈接;
(3)很好的與各類數據庫兼容(由於MyBatis使用JDBC來鏈接數據庫,因此只要JDBC支持的數據庫MyBatis都支持)。
(4)可以與Spring很好的集成;
(5)提供映射標籤,支持對象與數據庫的ORM字段關係映射;提供對象關係映射標籤,支持對象關係組件維護。
(1)SQL語句的編寫工做量較大,尤爲當字段多、關聯表多時,對開發人員編寫SQL語句的功底有必定要求。
(2)SQL語句依賴於數據庫,致使數據庫移植性差,不能隨意更換數據庫。
(1)MyBatis專一於SQL自己,是一個足夠靈活的DAO層解決方案。
(2)對性能的要求很高,或者需求變化較多的項目,如互聯網項目,MyBatis將是不錯的選擇。
(1)Mybatis和hibernate不一樣,它不徹底是一個ORM框架,由於MyBatis須要程序員本身編寫Sql語句。
(2)Mybatis直接編寫原生態sql,能夠嚴格控制sql執行性能,靈活度高,很是適合對關係數據模型要求不高的軟件開發,由於這類軟件需求變化頻繁,一但需求變化要求迅速輸出成果。可是靈活的前提是mybatis沒法作到數據庫無關性,若是須要實現支持多種數據庫的軟件,則須要自定義多套sql映射文件,工做量大。
(3)Hibernate對象/關係映射能力強,數據庫無關性好,對於關係模型要求高的軟件,若是用hibernate開發能夠節省不少代碼,提升效率。
#{}是預編譯處理,${}是字符串替換。
Mybatis在處理#{}時,會將sql中的#{}替換爲?號,調用PreparedStatement的set方法來賦值;
Mybatis在處理${}時,就是把${}替換成變量的值。
使用#{}能夠有效的防止SQL注入,提升系統安全性。
第1種: 經過在查詢的sql語句中定義字段名的別名,讓字段名的別名和實體類的屬性名一致。
第2種: 經過<resultMap>來映射字段名和實體類屬性名的一一對應的關係。
第1種:在Java代碼中添加sql通配符。
第2種:在sql語句中拼接通配符,會引發sql注入
Dao接口即Mapper接口。接口的全限名,就是映射文件中的namespace的值;接口的方法名,就是映射文件中Mapper的Statement的id值;接口方法內的參數,就是傳遞給sql的參數。
Mapper接口是沒有實現類的,當調用接口方法時,接口全限名+方法名拼接字符串做爲key值,可惟必定位一個MapperStatement。在Mybatis中,每個<select>、<insert>、<update>、<delete>標籤,都會被解析爲一個MapperStatement對象。
舉例:com.mybatis3.mappers.StudentDao.findStudentById,能夠惟一找到namespace爲com.mybatis3.mappers.StudentDao下面 id 爲 findStudentById 的 MapperStatement。
Mapper接口裏的方法,是不能重載的,由於是使用 全限名+方法名 的保存和尋找策略。Mapper 接口的工做原理是JDK動態代理,Mybatis運行時會使用JDK動態代理爲Mapper接口生成代理對象proxy,代理對象會攔截接口方法,轉而執行MapperStatement所表明的sql,而後將sql執行結果返回。
Mybatis使用RowBounds對象進行分頁,它是針對ResultSet結果集執行的內存分頁,而非物理分頁。能夠在sql內直接書寫帶有物理分頁的參數來完成物理分頁功能,也能夠使用分頁插件來完成物理分頁。分頁插件的基本原理是使用Mybatis提供的插件接口,實現自定義插件,在插件的攔截方法內攔截待執行的sql,而後重寫sql,根據dialect方言,添加對應的物理分頁語句和物理分頁參數。
第一種是使用<resultMap>標籤,逐必定義數據庫列名和對象屬性名之間的映射關係。
第二種是使用sql列的別名功能,將列的別名書寫爲對象屬性名。
有了列名與屬性名的映射關係後,Mybatis經過反射建立對象,同時使用反射給對象的屬性逐一賦值並返回,那些找不到映射關係的屬性,是沒法完成賦值的。
首先,建立一個簡單的insert語句:mapper.xml中
而後在java代碼中批量賦值:業務層調用dao層執行插入
在insert語句中開啓usegeneratedkeys=」true」 keyproperty=」id」
insert 方法老是返回一個int值 ,這個值表明的是插入的行數。
若是採用自增加策略,自動生成的鍵值在 insert 方法執行完後能夠被設置到傳入的參數對象中。
(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 註解:
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
try{
//映射文件的命名空間.SQL片斷的ID,就能夠調用對應的映射文件中的SQL
//因爲咱們的參數超過了兩個,而方法中只有一個Object參數收集,所以咱們使用Map集合來裝載咱們的參數
Map<String, Object> map = new HashMap();
map.put("start", start);
map.put("end", end);
return sqlSession.selectList("StudentID.pagination", map);
}catch(Exception e){
e.printStackTrace();
sqlSession.rollback();
throw e; }
finally{
MybatisUtil.closeSqlSession();
}
Mybatis動態sql能夠在Xml映射文件內,以標籤的形式編寫動態sql,執行原理是根據表達式的值 完成邏輯判斷並動態拼接sql的功能。
Mybatis提供了9種動態sql標籤:trim | where | set | foreach | if | choose | when | otherwise | bind。
<resultMap>、<parameterMap>、<sql>、<include>、<selectKey>,加上動態sql的9個標籤,其中<sql>爲sql片斷標籤,經過<include>標籤引入sql片斷,<selectKey>爲不支持自增的主鍵生成策略標籤。
不一樣的Xml映射文件,若是配置了namespace,那麼id能夠重複;若是沒有配置namespace,那麼id不能重複;
緣由就是namespace+id是做爲Map<String, MapperStatement>的key使用的,若是沒有namespace,就剩下id,那麼,id重複會致使數據互相覆蓋。有了namespace,天然id就能夠重複,namespace不一樣,namespace+id天然也就不一樣。
可是,在之前的Mybatis版本的namespace是可選的,不過新版本的namespace已是必須的了。
Hibernate屬於全自動ORM映射工具,使用Hibernate查詢關聯對象或者關聯集合對象時,能夠根據對象關係模型直接獲取,因此它是全自動的。而Mybatis在查詢關聯對象或關聯集合對象時,須要手動編寫sql來完成,因此,稱之爲半自動ORM映射工具。
association 一對一, 一對多 collection,多對多 discrimination
有聯合查詢和嵌套查詢,聯合查詢是幾個表聯合查詢,只查詢一次, 經過在resultMap裏面配置association節點配置一對一的類就能夠完成;
嵌套查詢是先查一個表,根據這個表裏面的結果的 外鍵id,去再另一個表裏面查詢數據,也是經過association配置,但另一個表的查詢經過select屬性配置。
有聯合查詢和嵌套查詢。聯合查詢是幾個表聯合查詢,只查詢一次,經過在resultMap裏面的collection節點配置一對多的類就能夠完成;嵌套查詢是先查一個表,根據這個表裏面的 結果的外鍵id,去再另一個表裏面查詢數據,也是經過配置collection,但另一個表的查詢經過select節點配置。
Mybatis僅支持association關聯對象和collection關聯集合對象的延遲加載,association指的就是一對一,collection指的就是一對多查詢。在Mybatis配置文件中,能夠配置是否啓用延遲加載lazyLoadingEnabled=true|false。
它的原理是,使用CGLIB建立目標對象的代理對象,當調用目標方法時,進入攔截器方法,好比調用a.getB().getName(),攔截器invoke()方法發現a.getB()是null值,那麼就會單獨發送事先保存好的查詢關聯B對象的sql,把B查詢上來,而後調用a.setB(b),因而a的對象b屬性就有值了,接着完成a.getB().getName()方法的調用。這就是延遲加載的基本原理。
固然了,不光是Mybatis,幾乎全部的包括Hibernate,支持延遲加載的原理都是同樣的。
1)一級緩存: 基於 PerpetualCache 的 HashMap 本地緩存,其存儲做用域爲 Session,當 Session flush 或 close 以後,該 Session 中的全部 Cache 就將清空,默認打開一級緩存。
2)二級緩存與一級緩存其機制相同,默認也是採用 PerpetualCache,HashMap 存儲,不一樣在於其存儲做用域爲 Mapper(Namespace),而且可自定義存儲源,如 Ehcache。默認不打開二級緩存,要開啓二級緩存,使用二級緩存屬性類須要實現Serializable序列化接口(可用來保存對象的狀態),可在它的映射文件中配置<cache/> ;
3)對於緩存數據更新機制,當某一個做用域(一級緩存 Session/二級緩存Namespaces)的進行了C/U/D 操做後,默認該做用域下全部 select 中的緩存將被 clear 掉並從新更新,若是開啓了二級緩存,則只根據配置判斷是否刷新。
接口綁定,就是在MyBatis中任意定義接口,而後把接口裏面的方法和SQL語句綁定, 咱們直接調用接口方法就能夠,這樣比起原來了SqlSession提供的方法咱們能夠有更加靈活的選擇和設置。
接口綁定有兩種實現方式,一種是經過註解綁定,就是在接口的方法上面加上 @Select、@Update等註解,裏面包含Sql語句來綁定;另一種就是經過xml裏面寫SQL來綁定, 在這種狀況下,要指定xml映射文件裏面的namespace必須爲接口的全路徑名。當Sql語句比較簡單時候,用註解綁定, 當SQL語句比較複雜時候,用xml綁定,通常用xml綁定的比較多。
① Mapper接口方法名和mapper.xml中定義的每一個sql的id相同;
② Mapper接口方法的輸入參數類型和mapper.xml中定義的每一個sql 的parameterType的類型相同;
③ Mapper接口方法的輸出參數類型和mapper.xml中定義的每一個sql的resultType的類型相同;
③ Mapper.xml文件中的namespace便是mapper接口的類路徑。
第一種:接口實現類繼承SqlSessionDaoSupport:使用此種方法須要編寫mapper接口,mapper接口實現類、mapper.xml文件。
(1)在sqlMapConfig.xml中配置mapper.xml的位置
<mappers>
<mapper resource="mapper.xml文件的地址" />
<mapper resource="mapper.xml文件的地址" />
</mappers>
(2)定義mapper接口
(3)實現類集成SqlSessionDaoSupport
mapper方法中能夠this.getSqlSession()進行數據增刪改查。
(4)spring 配置
<bean id=" " class="mapper接口的實現">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
第二種:使用org.mybatis.spring.mapper.MapperFactoryBean:
(1)在sqlMapConfig.xml中配置mapper.xml的位置,若是mapper.xml和mappre接口的名稱相同且在同一個目錄,這裏能夠不用配置
<mappers>
<mapper resource="mapper.xml文件的地址" />
<mapper resource="mapper.xml文件的地址" />
</mappers>
(2)定義mapper接口:
①mapper.xml中的namespace爲mapper接口的地址
②mapper接口中的方法名和mapper.xml中的定義的statement的id保持一致
③Spring中定義
<bean id="" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="mapper接口地址" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
第三種:使用mapper掃描器:
(1)mapper.xml文件編寫:
mapper.xml中的namespace爲mapper接口的地址;
mapper接口中的方法名和mapper.xml中的定義的statement的id保持一致;
若是將mapper.xml和mapper接口的名稱保持一致則不用在sqlMapConfig.xml中進行配置。
(2)定義mapper接口:
注意mapper.xml的文件名和mapper的接口名稱保持一致,且放在同一個目錄
(3)配置mapper掃描器:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="mapper接口包地址"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
(4)使用掃描器後從spring容器中獲取mapper的實現對象。
Mybatis僅能夠編寫針對ParameterHandler、ResultSetHandler、StatementHandler、Executor這4種接口的插件,Mybatis使用JDK的動態代理,爲須要攔截的接口生成代理對象以實現接口方法攔截功能,每當執行這4種接口對象的方法時,就會進入攔截方法,具體就是InvocationHandler的invoke()方法,固然,只會攔截那些你指定須要攔截的方法。
編寫插件:實現Mybatis的Interceptor接口並複寫intercept()方法,而後在給插件編寫註解,指定要攔截哪個接口的哪些方法便可,記住,別忘了在配置文件中配置你編寫的插件。
Hibernate的核心思想是ROM對象關係映射機制。它是將表與表之間的操做映射成對象與對象之間的操做。從數據庫中提取的信息會自動按照你設置的映射要求封裝成特色的對象,使得對對象的修改對應數據行的修改。
讀取並解析配置文件
讀取並解析映射信息,建立SessionFactory
打開Sesssion
建立事務Transation
持久化操做
提交事務
關閉Session
關閉SesstionFactory
使用Hibernate框架就不用咱們寫不少繁瑣的SQL語句。Hibernate實現了ORM,可以將對象映射成數據庫表,從而簡化咱們的開發!
經過設置屬性lazy進行設置是否須要懶加載
當Hibernate在查詢數據的時候,數據並無存在與內存中,當程序真正對數據的操做時,對象才存在與內存中,就實現了延遲加載,他節省了服務器的內存開銷,從而提升了服務器的性能。
它們經過配置文件中的many-to-one、one-to-many、many-to-many來實現類之間的關聯關係的。
Hibernate中對象的狀態:
臨時/瞬時狀態
持久化狀態
遊離狀態
new出來的對象是瞬時狀態->保存到數據庫中(受Session管理)就是持久化狀態->將session close掉就是遊離狀態
1)當即檢索:
優勢: 對應用程序徹底透明,無論對象處於持久化狀態,仍是遊離狀態,應用程序均可以方便的從一個對象導航到與它關聯的對象;
缺點: 1.select語句太多;2.可能會加載應用程序不須要訪問的對象白白浪費許多內存空間;
當即檢索:lazy=false;
2)延遲檢索:
優勢: 由應用程序決定須要加載哪些對象,能夠避免可執行多餘的select語句,以及避免加載應用程序不須要訪問的對象。所以能提升檢索性能,而且能節省內存空間;
缺點: 應用程序若是但願訪問遊離狀態代理類實例,必須保證他在持久化狀態時已經被初始化;
延遲加載:lazy=true;
3)迫切左外鏈接檢索:
優勢: 1對應用程序徹底透明,無論對象處於持久化狀態,仍是遊離狀態,應用程序均可以方便地衝一個對象導航到與它關聯的對象。2使用了外鏈接,select語句數目少;
缺點: 1 可能會加載應用程序不須要訪問的對象,白白浪費許多內存空間;2複雜的數據庫錶鏈接也會影響檢索性能;
預先抓取: fetch=「join」;
4種:
放入二級緩存的對象,只讀(Read-only);
非嚴格的讀寫(Nonstrict read/write)
讀寫; 放入二級緩存的對象能夠讀、寫(Read/write);
基於事務的策略(Transactional)
sorted collection是在內存中經過Java比較器進行排序的
ordered collection是在數據庫中經過order by進行排序的
對於比較大的數據集,爲了不在內存中對它們進行排序而出現 Java中的OutOfMemoryError,最好使用ordered collection。
一級緩存:
Hibenate中一級緩存,也叫作session的緩存,它能夠在session範圍內減小數據庫的訪問次數! 只在session範圍有效! Session關閉,一級緩存失效!
只要是持久化對象狀態的,都受Session管理,也就是說,都會在Session緩存中!
Session的緩存由hibernate維護,用戶不能操做緩存內容; 若是想操做緩存內容,必須經過hibernate提供的evit/clear方法操做。
二級緩存:
二級緩存是基於應用程序的緩存,全部的Session均可以使用
Hibernate提供的二級緩存有默認的實現,且是一種可插配的緩存框架!若是用戶想用二級緩存,只須要在hibernate.cfg.xml中配置便可; 不想用,直接移除,不影響代碼。
若是用戶以爲hibernate提供的框架框架很差用,本身能夠換其餘的緩存框架或本身實現緩存框架均可以。
Hibernate二級緩存:存儲的是經常使用的類
1、對象導航查詢(objectcomposition)
2、HQL查詢
一、 屬性查詢
二、 參數查詢、命名參數查詢
三、 關聯查詢
四、 分頁查詢
五、 統計函數
3、Criteria 查詢
4、SQLQuery本地SQL查詢
Ø 數據庫設計調整
Ø HQL優化
Ø API的正確使用(如根據不一樣的業務類型選用不一樣的集合及查詢API)
Ø 主配置參數(日誌,查詢緩存,fetch_size, batch_size等)
Ø 映射文件優化(ID生成策略,二級緩存,延遲加載,關聯優化)
Ø 一級緩存的管理
Ø 針對二級緩存,還有許多特有的策略
詳情可參考資料:
inverse屬性默認是false,就是說關係的兩端都來維護關係。
好比Student和Teacher是多對多關係,用一箇中間表TeacherStudent維護。Gp)
若是Student這邊inverse=」true」, 那麼關係由另外一端Teacher維護,就是說當插入Student時,不會操做TeacherStudent表(中間表)。只有Teacher插入或刪除時纔會觸發對中間表的操做。因此兩邊都inverse=」true」是不對的,會致使任何操做都不觸發對中間表的影響;當兩邊都inverse=」false」或默認時,會致使在中間表中插入兩次關係。
若是表之間的關聯關係是「一對多」的話,那麼inverse只能在「一」的一方來配置!
jdbc:手動
手動寫sql
delete、insert、update要將對象的值一個一個取出傳到sql中,不能直接傳入一個對象。
select:返回的是一個resultset,要從ResultSet中一行一行、一個字段一個字段的取出,而後封裝到一個對象中,不直接返回一個對象。
ibatis的特色:半自動化
sql要手動寫
delete、insert、update:直接傳入一個對象
select:直接返回一個對象
hibernate:全自動
不寫sql,自動封裝
delete、insert、update:直接傳入一個對象
select:直接返回一個對象
建索引
減小表之間的關聯
優化sql,儘可能讓sql很快定位數據,不要讓sql作全表查詢,應該走索引,把數據量大的表排在前面
簡化查詢字段,沒用的字段不要,已經對返回結果的控制,儘可能返回少許數據
SessionFactory 是Hibrenate單例數據存儲和線程安全的,以致於能夠多線程同時訪問。一個SessionFactory 在啓動的時候只能創建一次。SessionFactory應該包裝各類單例以致於它能很簡單的在一個應用代碼中儲存.
get()當即查詢
load()懶加載
1)get若是沒有找到會返回null, load若是沒有找到會拋出異常。
2)get會先查一級緩存, 再查二級緩存,而後查數據庫;load會先查一級緩存,若是沒有找到,就建立代理對象, 等須要的時候去查詢二級緩存和數據庫。
若是session中存在相同持久化標識(identifier)的實例,用用戶給出的對象的狀態覆蓋舊有的持久實例
若是session沒有相應的持久實例,則嘗試從數據庫中加載,或建立新的持久化實例,最後返回該持久實例
用戶給出的這個對象沒有被關聯到session上,它依舊是託管的
persist不保證當即執行,可能要等到flush;
persist不更新緩存;
save, 把一個瞬態的實例持久化標識符,及時的產生,它要返回標識符,因此它會當即執行Sql insert
使用 save() 方法保存持久化對象時,該方法返回該持久化對象的標識屬性值(即對應記錄的主鍵值);
使用 persist() 方法來保存持久化對象時,該方法沒有任何返回值。
主鍵的自動生成策略
identity 自增加(mysql,db2)
sequence 自增加(序列), oracle中自增加是以序列方法實現**
native 自增加【會根據底層數據庫自增加的方式選擇identity或sequence】
若是是mysql數據庫, 採用的自增加方式是identity
若是是oracle數據庫, 使用sequence序列的方式實現自增加
increment 自增加(會有併發訪問的問題,通常在服務器集羣環境使用會存在問題。)
指定主鍵生成策略爲手動指定主鍵的值
assigned
指定主鍵生成策略爲UUID生成的值
uuid
foreign(外鍵的方式)
一、getCurrentSession會綁定當前線程,而openSession不會,由於咱們把hibernate交給咱們的spring來管理以後,咱們是有事務配置,這個有事務的線程就會綁定當前的工廠裏面的每個session,而openSession是建立一個新session。
二、getCurrentSession事務是有spring來控制的,而openSession須要咱們手動開啓和手動提交事務,
三、getCurrentSession是不須要咱們手動關閉的,由於工廠會本身管理,而openSession須要咱們手動關閉。
四、而getCurrentSession須要咱們手動設置綁定事務的機制,有三種設置方式,jdbc本地的Thread、JTA、第三種是spring提供的事務管理機制org.springframework.orm.hibernate4.SpringSessionContext,並且srping默認使用該種事務管理機制
命名查詢指的是用<sql-query>標籤在影射文檔中定義的SQL查詢,能夠經過使用Session.getNamedQuery()方法對它進行調用。命名查詢使你能夠使用你所指定的一個名字拿到某個特定的查詢。
Hibernate中的命名查詢能夠使用註解來定義,也能夠使用我前面提到的xml影射問句來定義。在Hibernate中,@NameQuery用來定義單個的命名查詢,@NameQueries用來定義多個命名查詢。
每一個Hibernate實體類必須包含一個 無參數的構造器, 這是由於Hibernate框架要使用Reflection API,經過調用Class.newInstance()來建立這些實體類的實例。若是在實體類中找不到無參數的構造器,這個方法就會拋出一個InstantiationException異常。
你能夠將Hibernate的實體類定義爲final類,但這種作法並很差。由於Hibernate會使用代理模式在延遲關聯的狀況下提升性能,若是你把實體類定義成final類以後,由於 Java不容許對final類進行擴展,因此Hibernate就沒法再使用代理了, 如此一來就限制了使用能夠提高性能的手段。
Spring是一個輕量級的IoC和AOP容器框架。是爲Java應用程序提供基礎性服務的一套框架,目的是用於簡化企業應用程序的開發,它使得開發者只須要關心業務需求。常見的配置方式有三種:基於XML的配置、基於註解的配置、基於Java的配置。
主要由如下幾個模塊組成:
Spring Core:核心類庫,提供IOC服務;
Spring Context:提供框架式的Bean訪問方式,以及企業級功能(JNDI、定時任務等);
Spring AOP:AOP服務;
Spring DAO:對JDBC的抽象,簡化了數據訪問異常的處理;
Spring ORM:對現有的ORM框架的支持;
Spring Web:提供了基本的面向Web的綜合特性,例如多方文件上傳;
Spring MVC:提供面向Web應用的Model-View-Controller實現。
(1)spring屬於低侵入式設計,代碼的污染極低;
(2)spring的DI機制將對象之間的依賴關係交由框架處理,減低組件的耦合性;
(3)Spring提供了AOP技術,支持將一些通用任務,如安全、事務、日誌、權限等進行集中式管理,從而提供更好的複用。
(4)spring對於主流的應用框架提供了集成支持。
OOP面向對象,容許開發者定義縱向的關係,但並適用於定義橫向的關係,致使了大量代碼的重複,而不利於各個模塊的重用。
AOP,通常稱爲面向切面,做爲面向對象的一種補充,用於將那些與業務無關,但卻對多個對象產生影響的公共行爲和邏輯,抽取並封裝爲一個可重用的模塊,這個模塊被命名爲「切面」(Aspect),減小系統中的重複代碼,下降了模塊間的耦合度,同時提升了系統的可維護性。可用於權限認證、日誌、事務處理。
AOP實現的關鍵在於 代理模式,AOP代理主要分爲靜態代理和動態代理。靜態代理的表明爲AspectJ;動態代理則以Spring AOP爲表明。
(1)AspectJ是靜態代理的加強,所謂靜態代理,就是AOP框架會在編譯階段生成AOP代理類,所以也稱爲編譯時加強,他會在編譯階段將AspectJ(切面)織入到Java字節碼中,運行的時候就是加強以後的AOP對象。
(2)Spring AOP使用的動態代理,所謂的動態代理就是說AOP框架不會去修改字節碼,而是每次運行時在內存中臨時爲方法生成一個AOP對象,這個AOP對象包含了目標對象的所有方法,而且在特定的切點作了加強處理,並回調原對象的方法。
Spring AOP中的動態代理主要有兩種方式,JDK動態代理和CGLIB動態代理:
①JDK動態代理只提供接口的代理,不支持類的代理。核心InvocationHandler接口和Proxy類,InvocationHandler 經過invoke()方法反射來調用目標類中的代碼,動態地將橫切邏輯和業務編織在一塊兒;接着,Proxy利用 InvocationHandler動態建立一個符合某一接口的的實例, 生成目標類的代理對象。
②若是代理類沒有實現 InvocationHandler 接口,那麼Spring AOP會選擇使用CGLIB來動態代理目標類。CGLIB(Code Generation Library),是一個代碼生成的類庫,能夠在運行時動態的生成指定類的一個子類對象,並覆蓋其中特定方法並添加加強代碼,從而實現AOP。CGLIB是經過繼承的方式作的動態代理,所以若是某個類被標記爲final,那麼它是沒法使用CGLIB作動態代理的。
(3)靜態代理與動態代理區別在於生成AOP代理對象的時機不一樣,相對來講AspectJ的靜態代理方式具備更好的性能,可是AspectJ須要特定的編譯器進行處理,而Spring AOP則無需特定的編譯器處理。
InvocationHandler 的 invoke(Object proxy,Method method,Object[] args):proxy是最終生成的代理實例; method 是被代理目標實例的某個具體方法; args 是被代理目標實例某個方法的具體入參, 在方法反射調用時使用。
(1)IOC就是控制反轉,是指建立對象的控制權的轉移,之前建立對象的主動權和時機是由本身把控的,而如今這種權力轉移到Spring容器中,並由容器根據配置文件去建立實例和管理各個實例之間的依賴關係,對象與對象之間鬆散耦合,也利於功能的複用。DI依賴注入,和控制反轉是同一個概念的不一樣角度的描述,即 應用程序在運行時依賴IoC容器來動態注入對象須要的外部資源。
(2)最直觀的表達就是,IOC讓對象的建立不用去new了,能夠由spring自動生產,使用java的反射機制,根據配置文件在運行時動態的去建立對象以及管理對象,並調用對象的方法的。
(3)Spring的IOC有三種注入方式 :構造器注入、setter方法注入、根據註解注入。
IoC讓相互協做的組件保持鬆散的耦合,而AOP編程容許你把遍及於應用各層的功能分離出來造成可重用的功能組件。
BeanFactory和ApplicationContext是Spring的兩大核心接口,均可以當作Spring的容器。其中ApplicationContext是BeanFactory的子接口。
(1)BeanFactory:是Spring裏面最底層的接口,包含了各類Bean的定義,讀取bean配置文檔,管理bean的加載、實例化,控制bean的生命週期,維護bean之間的依賴關係。ApplicationContext接口做爲BeanFactory的派生,除了提供BeanFactory所具備的功能外,還提供了更完整的框架功能:
①繼承MessageSource,所以支持國際化。
②統一的資源文件訪問方式。
③提供在監聽器中註冊bean的事件。
④同時加載多個配置文件。
⑤載入多個(有繼承關係)上下文 ,使得每個上下文都專一於一個特定的層次,好比應用的web層。
(2)①BeanFactroy採用的是延遲加載形式來注入Bean的,即只有在使用到某個Bean時(調用getBean()),纔對該Bean進行加載實例化。這樣,咱們就不能發現一些存在的Spring的配置問題。若是Bean的某一個屬性沒有注入,BeanFacotry加載後,直至第一次使用調用getBean方法纔會拋出異常。
②ApplicationContext,它是在容器啓動時,一次性建立了全部的Bean。這樣,在容器啓動時,咱們就能夠發現Spring中存在的配置錯誤,這樣有利於檢查所依賴屬性是否注入。 ApplicationContext啓動後預載入全部的單實例Bean,經過預載入單實例bean ,確保當你須要的時候,你就不用等待,由於它們已經建立好了。
③相對於基本的BeanFactory,ApplicationContext 惟一的不足是佔用內存空間。當應用程序配置Bean較多時,程序啓動較慢。
(3)BeanFactory一般以編程的方式被建立,ApplicationContext還能以聲明的方式建立,如使用ContextLoader。
(4)BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但二者之間的區別是:BeanFactory須要手動註冊,而ApplicationContext則是自動註冊。
首先說一下Servlet的生命週期:實例化,初始init,接收請求service,銷燬destroy;
Spring上下文中的Bean生命週期也相似,以下:
(1)實例化Bean:
對於BeanFactory容器,當客戶向容器請求一個還沒有初始化的bean時,或初始化bean的時候須要注入另外一個還沒有初始化的依賴時,容器就會調用createBean進行實例化。對於ApplicationContext容器,當容器啓動結束後,經過獲取BeanDefinition對象中的信息,實例化全部的bean。
(2)設置對象屬性(依賴注入):
實例化後的對象被封裝在BeanWrapper對象中,緊接着,Spring根據BeanDefinition中的信息 以及 經過BeanWrapper提供的設置屬性的接口完成依賴注入。
(3)處理Aware接口:
接着,Spring會檢測該對象是否實現了xxxAware接口,並將相關的xxxAware實例注入給Bean:
①若是這個Bean已經實現了BeanNameAware接口,會調用它實現的setBeanName(String beanId)方法,此處傳遞的就是Spring配置文件中Bean的id值;
②若是這個Bean已經實現了BeanFactoryAware接口,會調用它實現的setBeanFactory()方法,傳遞的是Spring工廠自身。
③若是這個Bean已經實現了ApplicationContextAware接口,會調用setApplicationContext(ApplicationContext)方法,傳入Spring上下文;
(4)BeanPostProcessor:
若是想對Bean進行一些自定義的處理,那麼可讓Bean實現了BeanPostProcessor接口,那將會調用postProcessBeforeInitialization(Object obj, String s)方法。
(5)InitializingBean 與 init-method:
若是Bean在Spring配置文件中配置了 init-method 屬性,則會自動調用其配置的初始化方法。
(6)若是這個Bean實現了BeanPostProcessor接口,將會調用postProcessAfterInitialization(Object obj, String s)方法;因爲這個方法是在Bean初始化結束時調用的,因此能夠被應用於內存或緩存技術;
以上幾個步驟完成後,Bean就已經被正確建立了,以後就能夠使用這個Bean了。
(7)DisposableBean:
當Bean再也不須要時,會通過清理階段,若是Bean實現了DisposableBean這個接口,會調用其實現的destroy()方法;
(8)destroy-method:
最後,若是這個Bean的Spring配置中配置了destroy-method屬性,會自動調用其配置的銷燬方法。
Spring容器中的bean能夠分爲5個範圍:
(1)singleton:默認,每一個容器中只有一個bean的實例,單例的模式由BeanFactory自身來維護。
(2)prototype:爲每個bean請求提供一個實例。
(3)request:爲每個網絡請求建立一個實例,在請求完成之後,bean會失效並被垃圾回收器回收。
(4)session:與request範圍相似,確保每一個session中有一個bean的實例,在session過時後,bean會隨之失效。
(5)global-session:全局做用域,global-session和Portlet應用相關。當你的應用部署在Portlet容器中工做時,它包含不少portlet。若是你想要聲明讓全部的portlet共用全局的存儲變量的話,那麼這全局變量須要存儲在global-session中。全局做用域與Servlet中的session做用域效果相同。
Spring框架並無對單例bean進行任何多線程的封裝處理。關於單例bean的線程安全和併發問題須要開發者自行去搞定。但實際上,大部分的Spring bean並無可變的狀態(好比Serview類和DAO類),因此在某種程度上說Spring的單例bean是線程安全的。若是你的bean有多種狀態的話(好比 View Model 對象),就須要自行保證線程安全。最淺顯的解決辦法就是將多態bean的做用域由「singleton」變動爲「prototype」。
在通常狀況下,只有無狀態的Bean才能夠在多線程環境下共享,在Spring中,絕大部分Bean均可以聲明爲singleton做用域,由於Spring對一些Bean中非線程安全狀態採用ThreadLocal進行處理,解決線程安全問題。
ThreadLocal和線程同步機制都是爲了解決多線程中相同變量的訪問衝突問題。同步機制採用了「時間換空間」的方式,僅提供一份變量,不一樣的線程在訪問前須要獲取鎖,沒得到鎖的線程則須要排隊。而ThreadLocal採用了「空間換時間」的方式。
ThreadLocal會爲每個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問衝突。由於每個線程都擁有本身的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,能夠把不安全的變量封裝進ThreadLocal。
(1)Set方法注入;
(2)構造器注入:①經過index設置參數的位置;②經過type設置參數類型;
(3)靜態工廠注入;
(4)實例工廠;
在spring中,對象無需本身查找或建立與其關聯的其餘對象,由容器負責把須要相互協做的對象引用賦予各個對象,使用autowire來配置自動裝載模式。
在Spring框架xml配置中共有5種自動裝配:
(1)no:默認的方式是不進行自動裝配的,經過手工設置ref屬性來進行裝配bean。
(2)byName:經過bean的名稱進行自動裝配,若是一個bean的 property 與另外一bean 的name 相同,就進行自動裝配。
(3)byType:經過參數的數據類型進行自動裝配。
(4)constructor:利用構造函數進行裝配,而且構造函數的參數經過byType進行裝配。
(5)autodetect:自動探測,若是有構造方法,經過 construct的方式自動裝配,不然使用 byType的方式自動裝配。
基於註解的方式:
使用@Autowired註解來自動裝配指定的bean。在使用@Autowired註解以前須要在Spring配置文件進行配置,<context:annotation-config />。在啓動spring IoC時,容器自動裝載了一個AutowiredAnnotationBeanPostProcessor後置處理器,當容器掃描到@Autowied、@Resource或@Inject時,就會在IoC容器自動查找須要的bean,並裝配給該對象的屬性。在使用@Autowired時,首先在容器中查詢對應類型的bean:
若是查詢結果恰好爲一個,就將該bean裝配給@Autowired指定的數據;
若是查詢的結果不止一個,那麼@Autowired會根據名稱來查找;
若是上述查找的結果爲空,那麼會拋出異常。解決方法時,使用required=false。
@Autowired可用於:構造函數、成員變量、Setter方法
注:@Autowired和@Resource之間的區別
(1) @Autowired默認是按照類型裝配注入的,默認狀況下它要求依賴對象必須存在(能夠設置它required屬性爲false)。
(2) @Resource默認是按照名稱來裝配注入的,只有當找不到與名稱匹配的bean纔會按照類型來裝配注入。
(1)工廠模式:BeanFactory就是簡單工廠模式的體現,用來建立對象的實例;
(2)單例模式:Bean默認爲單例模式。
(3)代理模式:Spring的AOP功能用到了JDK的動態代理和CGLIB字節碼生成技術;
(4)模板方法:用來解決代碼重複的問題。好比. RestTemplate, JmsTemplate, JpaTemplate。
(5)觀察者模式:定義對象鍵一種一對多的依賴關係,當一個對象的狀態發生改變時,全部依賴於它的對象都會獲得通知被制動更新,如Spring中listener的實現--ApplicationListener。
Spring事務的本質其實就是數據庫對事務的支持,沒有數據庫的事務支持,spring是沒法提供事務功能的。真正的數據庫層的事務提交和回滾是經過binlog或者redo log實現的。
(1)Spring事務的種類:
spring支持編程式事務管理和聲明式事務管理兩種方式:
①編程式事務管理使用TransactionTemplate。
②聲明式事務管理創建在AOP之上的。其本質是經過AOP功能,對方法先後進行攔截,將事務處理的功能編織到攔截的方法中,也就是在目標方法開始以前加入一個事務,在執行完目標方法以後根據執行狀況提交或者回滾事務。
聲明式事務最大的優勢就是不須要在業務邏輯代碼中摻瑣事務管理的代碼,只需在配置文件中作相關的事務規則聲明或經過@Transactional註解的方式,即可以將事務規則應用到業務邏輯中。
聲明式事務管理要優於編程式事務管理,這正是spring倡導的非侵入式的開發方式,使業務代碼不受污染,只要加上註解就能夠得到徹底的事務支持。惟一不足地方是,最細粒度只能做用到方法級別,沒法作到像編程式事務那樣能夠做用到代碼塊級別。
(2)spring的事務傳播行爲:
spring事務的傳播行爲說的是,當多個事務同時存在的時候,spring如何處理這些事務的行爲。
① PROPAGATION_REQUIRED:若是當前沒有事務,就建立一個新事務,若是當前存在事務,就加入該事務,該設置是最經常使用的設置。
② PROPAGATION_SUPPORTS:支持當前事務,若是當前存在事務,就加入該事務,若是當前不存在事務,就以非事務執行。‘
③ PROPAGATION_MANDATORY:支持當前事務,若是當前存在事務,就加入該事務,若是當前不存在事務,就拋出異常。
④ PROPAGATION_REQUIRES_NEW:建立新事務,不管當前存不存在事務,都建立新事務。
⑤ PROPAGATION_NOT_SUPPORTED:以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。
⑥ PROPAGATION_NEVER:以非事務方式執行,若是當前存在事務,則拋出異常。
⑦ PROPAGATION_NESTED:若是當前存在事務,則在嵌套事務內執行。若是當前沒有事務,則按REQUIRED屬性執行。
(3)Spring中的隔離級別:
① ISOLATION_DEFAULT:這是個 PlatfromTransactionManager 默認的隔離級別,使用數據庫默認的事務隔離級別。
② ISOLATION_READ_UNCOMMITTED:讀未提交,容許另一個事務能夠看到這個事務未提交的數據。
③ ISOLATION_READ_COMMITTED:讀已提交,保證一個事務修改的數據提交後才能被另外一事務讀取,並且能看到該事務對已有記錄的更新。
④ ISOLATION_REPEATABLE_READ:可重複讀,保證一個事務修改的數據提交後才能被另外一事務讀取,可是不能看到該事務對已有記錄的更新。
⑤ ISOLATION_SERIALIZABLE:一個事務在執行的過程當中徹底看不到其餘事務對數據庫所作的更新。
1三、Spring框架中有哪些不一樣類型的事件?
Spring 提供瞭如下5種標準的事件:
(1)上下文更新事件(ContextRefreshedEvent):在調用ConfigurableApplicationContext 接口中的refresh()方法時被觸發。
(2)上下文開始事件(ContextStartedEvent):當容器調用ConfigurableApplicationContext的Start()方法開始/從新開始容器時觸發該事件。
(3)上下文中止事件(ContextStoppedEvent):當容器調用ConfigurableApplicationContext的Stop()方法中止容器時觸發該事件。
(4)上下文關閉事件(ContextClosedEvent):當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的全部單例Bean都被銷燬。
(5)請求處理事件(RequestHandledEvent):在Web應用中,當一個http請求(request)結束觸發該事件。
若是一個bean實現了ApplicationListener接口,當一個ApplicationEvent 被髮布之後,bean會自動被通知。
1四、解釋一下Spring AOP裏面的幾個名詞:
(1)切面(Aspect):被抽取的公共模塊,可能會橫切多個對象。 在Spring AOP中,切面能夠使用通用類(基於模式的風格) 或者在普通類中以 @AspectJ 註解來實現。
(2)鏈接點(Join point):指方法,在Spring AOP中,一個鏈接點 老是 表明一個方法的執行。
(3)通知(Advice):在切面的某個特定的鏈接點(Join point)上執行的動做。通知有各類類型,其中包括「around」、「before」和「after」等通知。許多AOP框架,包括Spring,都是以攔截器作通知模型, 並維護一個以鏈接點爲中心的攔截器鏈。
(4)切入點(Pointcut):切入點是指 咱們要對哪些Join point進行攔截的定義。經過切入點表達式,指定攔截的方法,好比指定攔截add*、search*。
(5)引入(Introduction):(也被稱爲內部類型聲明(inter-type declaration))。聲明額外的方法或者某個類型的字段。Spring容許引入新的接口(以及一個對應的實現)到任何被代理的對象。例如,你能夠使用一個引入來使bean實現 IsModified 接口,以便簡化緩存機制。
(6)目標對象(Target Object): 被一個或者多個切面(aspect)所通知(advise)的對象。也有人把它叫作 被通知(adviced) 對象。 既然Spring AOP是經過運行時代理實現的,這個對象永遠是一個 被代理(proxied) 對象。
(7)織入(Weaving):指把加強應用到目標對象來建立新的代理對象的過程。Spring是在運行時完成織入。
切入點(pointcut)和鏈接點(join point)匹配的概念是AOP的關鍵,這使得AOP不一樣於其它僅僅提供攔截功能的舊技術。 切入點使得定位通知(advice)可獨立於OO層次。 例如,一個提供聲明式事務管理的around通知能夠被應用到一組橫跨多個對象中的方法上(例如服務層的全部業務操做)。
(1)前置通知(Before advice):在某鏈接點(join point)以前執行的通知,但這個通知不能阻止鏈接點前的執行(除非它拋出一個異常)。
(2)返回後通知(After returning advice):在某鏈接點(join point)正常完成後執行的通知:例如,一個方法沒有拋出任何異常,正常返回。
(3)拋出異常後通知(After throwing advice):在方法拋出異常退出時執行的通知。
(4)後通知(After (finally) advice):當某鏈接點退出的時候執行的通知(不管是正常返回仍是異常退出)。
(5)環繞通知(Around Advice):包圍一個鏈接點(join point)的通知,如方法調用。這是最強大的一種通知類型。 環繞通知能夠在方法調用先後完成自定義的行爲。它也會選擇是否繼續執行鏈接點或直接返回它們本身的返回值或拋出異常來結束執行。 環繞通知是最經常使用的一種通知類型。大部分基於攔截的AOP框架,例如Nanning和JBoss4,都只提供環繞通知。
同一個aspect,不一樣advice的執行順序:
①沒有異常狀況下的執行順序:
around before advice
before advice
target method 執行
around after advice
after advice
afterReturning
②有異常狀況下的執行順序:
around before advice
before advice
target method 執行
around after advice
after advice
afterThrowing:異常發生
java.lang.RuntimeException: 異常發生
Spring Boot 是 Spring 開源組織下的子項目,是 Spring 組件一站式解決方案,主要是簡化了使用 Spring 的難度,簡省了繁重的配置,提供了各類啓動器,開發者能快速上手。集成了44種服務。
Spring Boot 優勢很是多,如:
獨立運行
簡化配置
應用監控(本地調試生產環境)
上手容易
Spring Boot 的核心配置文件是 application 和 bootstrap 配置文件。
application 配置文件這個容易理解,主要用於 Spring Boot 項目的自動化配置。
bootstrap 配置文件有如下幾個應用場景。
使用 Spring Cloud Config 配置中心時,這時須要在 bootstrap 配置文件中添加鏈接到配置中心的配置屬性來加載外部配置中心的配置信息;
一些固定的不能被覆蓋的屬性;
一些加密/解密的場景;
具體請看這篇文章《Spring Boot 核心配置文件詳解》。
.properties 和 .yml,它們的區別主要是書寫格式不一樣。
1).properties
app.user.name = javastack
2).yml
app:
user:
name: javastack
另外,.yml 格式不支持 @PropertySource 註解導入配置。
他們都要求層級關係。
啓動類上面的註解是@SpringBootApplication,它也是 Spring Boot 的核心註解,主要組合包含了如下 3 個註解:
@SpringBootConfiguration:組合了 @Configuration 註解,實現配置文件的功能。
@EnableAutoConfiguration:打開自動配置的功能,也能夠關閉某個自動配置的選項,如關閉數據源自動配置功能@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。
@ComponentScan:Spring組件掃描。
1)繼承spring-boot-starter-parent項目
2)導入spring-boot-dependencies項目依賴
能夠不須要,內置了 Tomcat/ Jetty 等容器。
1)打包用命令或者放到容器中運行
2)用 Maven/ Gradle 插件運行
3)直接執行 main 方法運行
註解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自動配置的核心,首先它得是一個配置文件,其次根據類路徑下是否有這個類去自動配置。
cn
+- javastack
+- MyApplication.java
|
+- customer
| +- Customer.java
| +- CustomerController.java
| +- CustomerService.java
| +- CustomerRepository.java
|
+- order
+- Order.java
+- OrderController.java
+- OrderService.java
+- OrderRepository.java
Application類要處於bean的最上一層,不然掃描不到層級高於它的bean。這個目錄結構是主流及推薦的作法,而在主入口類上加上 @SpringBootApplication 註解來開啓 Spring Boot 的各項能力,如自動配置、組件掃描等。具體看這篇文章《Spring Boot 主類及目錄結構介紹》。
Starters能夠理解爲啓動器,它包含了一系列能夠集成到應用裏面的依賴包,你能夠一站式集成 Spring 及其餘技術,而不須要處處找示例代碼和依賴包。如你想使用 Spring JPA 訪問數據庫,只要加入 spring-boot-starter-data-jpa 啓動器依賴就能使用了。
Starters包含了許多項目中須要用到的依賴,它們能快速持續的運行,都是一系列獲得支持的管理傳遞性依賴。具體請看這篇文章《Spring Boot Starters啓動器》。
能夠實現接口 ApplicationRunner 或者 CommandLineRunner,這兩個接口實現方式同樣,它們都只提供了一個 run 方法,具體請看這篇文章《Spring Boot Runner啓動器》。
Spring Boot 能夠經過 @PropertySource,@Value,@Environment, @ConfigurationProperties 來綁定變量,具體請看這篇文章《Spring Boot讀取配置的幾種方式》。
Spring Boot 支持 Java Util Logging, Log4j2, Lockback 做爲日誌框架,若是你使用 Starters 啓動器,Spring Boot 將使用 Logback 做爲默認日誌框架,具體請看這篇文章《Spring Boot日誌集成》。
主要有兩種方式:
Spring Loaded
Spring-boot-devtools
在 Spring Boot 裏面,能夠使用如下幾種方式來加載配置。
1)properties文件;
2)YAML文件;
3)系統環境變量;
4)命令行參數;
提供多套配置文件,如:
applcation.properties
application-dev.properties
application-test.properties
application-prod.properties
運行時指定具體的配置文件,具體請看這篇文章《Spring Boot Profile 不一樣環境配置》。
能夠兼容,使用 @ImportResource 註解導入老 Spring 項目配置文件。
在生產中使用HTTPS
使用Snyk檢查你的依賴關係
升級到最新版本
啓用CSRF保護
使用內容安全策略防止XSS攻擊
配置變動
JDK 版本升級
第三方類庫升級
響應式 Spring 編程支持
HTTP/2 支持
配置屬性綁定
更多改進與增強…
事務是一種機制,一個操做序列,它包含了一組數據庫操做命令,並當作一個總體提交。要麼都執行,要麼都不執行。
*原子性Atomicity:不可分割的操做單元,事務中全部操做,要麼所有成功;要麼撤回到執行事務以前的狀態
*一致性Consistency:若是在執行事務以前數據庫是一致的,那麼在執行事務以後數據庫也仍是一致的;
*隔離性Isolation:事務操做之間彼此獨立和透明互不影響。事務獨立運行。這一般使用鎖來實現。一個事務處理後的結果,影響了其餘事務,那麼其餘事務會撤回。事務的100%隔離,須要犧牲速度。
*持久性Durability:事務一旦提交,其結果就是永久的。即使發生系統故障,也能恢復。
①未提交讀(Read Uncommitted):容許髒讀,其餘事務只要修改了數據,即便未提交,本事務也能看到修改後的數據值。也就是可能讀取到其餘會話中未提交事務修改的數據
②提交讀(Read Committed):只能讀取到已經提交的數據。Oracle等多數數據庫默認都是該級別 (不重複讀)。
③可重複讀(Repeated Read):可重複讀。不管其餘事務是否修改並提交了數據,在這個事務中看到的數據值始終不受其餘事務影響。
④串行讀(Serializable):徹底串行化的讀,每次讀都須要得到表級共享鎖,讀寫相互都會阻塞
MySQL數據庫(InnoDB引擎)默認使用可重複讀( Repeatable read)
數據庫索引,是數據庫管理系統中一個排序的數據結構,以協助快速查詢、更新數據庫表中數據。採起的是空間換時間的概念。
MyISAM引擎和InnoDB引擎使用B+Tree做爲索引結構
index ---- 普通索引,數據能夠重複,沒有任何限制。
unique ---- 惟一索引,要求索引列的值必須惟一,但容許有空值;若是是組合索引,那麼列值的組合必須惟一。
primary key ---- 主鍵索引,是一種特殊的惟一索引,一個表只能有一個主鍵,不容許有空值,通常是在建立表的同時建立主鍵索引。
組合索引 ---- 在多個字段上建立的索引,只有在查詢條件中使用了建立索引時的第一個字段,索引纔會被使用。
fulltext ---- 全文索引,是對於大表的文本域:char,varchar,text列才能建立全文索引,主要用於查找文本中的關鍵字,並非直接與索引中的值進行比較。fulltext更像是一個搜索引擎,配合match against操做使用,而不是通常的where語句加like。
注:全文索引目前只有MyISAM存儲引擎支持全文索引,InnoDB引擎5.6如下版本還不支持全文索引
全部存儲引擎對每一個表至少支持16個索引,總索引長度至少爲256字節,索引有兩種存儲類型,包括B型樹索引和哈希索引。
索引能夠提升查詢的速度,可是建立和維護索引須要耗費時間,同時也會影響插入的速度,若是須要插入大量的數據時,最好是先刪除索引,插入數據後再創建索引。
假設index(a,b,c)
1)最左前綴匹配:模糊查詢時,使用%匹配時:’a%‘會使用索引,’%a‘不會使用索引
2)條件中有or,索引不會生效
3) a and c,a生效,c不生效
b and c,都不生效
檢測索引的效果:
show status like '%handler_read%'越大越好
DDL:數據定義語言(create drop)
DML:數據操做語句(insert update delete)
DQL:數據查詢語句(select )
DCL:數據控制語句,進行受權和權限回收(grant revoke)
TPL:數據事務語句(commit collback savapoint)
第一範式:確保每列的原子性,確保每列都是最小的不可再分割的數據單元。
第二範式:確保表中的每列都和主鍵相關。
第三範式:確保每列都和主鍵直接相關,而不是間接相關。除了主鍵列,其餘的列和列之間不存在依賴關係。
*髒讀: 是指事務T1將某一值修改,而後事務T2讀取該值,此後T1由於某種緣由撤銷對該值的修改,這就致使了T2所讀取到的數據是無效的。
*不可重複讀 :是指在數據庫訪問時,一個事務範圍內的兩次相同查詢卻返回了不一樣數據。在一個事務內屢次讀同一數據。在這個事務尚未結束時,另一個事務也訪問該同一數據。那麼在第一個事務中的兩次讀數據之間,因爲第二個事務的修改,第一個事務兩次讀到的的數據多是不同的。這樣在一個事務內兩次讀到的數據是不同的,所以稱爲是不可重複讀。
*幻讀: 是指當事務不是獨立執行時發生的一種現象,好比第一個事務對一個表中的數據進行了修改,這種修改涉及到表中的所有數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那麼就會發生,操做第一個事務的用戶發現表中還有沒有修改的數據行,就好象發生了幻覺同樣。
不可重複讀&幻讀區別:
若是使用鎖機制來實現這兩種隔離級別,在可重複讀中,該sql第一次讀取到數據後,就將這些數據加鎖,其它事務沒法修改這些數據,就能夠實現可重複讀了。但這種方法卻沒法鎖住insert的數據,因此當事務A先前讀取了數據,或者修改了所有數據,事務B仍是能夠insert數據提交,這時事務A就會發現莫名其妙多了一條以前沒有的數據,這就是幻讀,不能經過行鎖來避免。須要Serializable隔離級別 ,讀用讀鎖,寫用寫鎖,讀鎖和寫鎖互斥,這麼作能夠有效的避免幻讀、不可重複讀、髒讀等問題,但會極大的下降數據庫的併發能力。
不可重複讀重點在於update和delete,而幻讀的重點在於insert。如何經過鎖機制來解決他們產生的問題
1)MyISAM 不支持事務,不支持外鍵,優點是訪問速度快,對事務完整性沒有要求,或者以select、insert爲主的能夠使用
2)InnoDB 支持事務,外鍵約束,自增,寫的效率差一些,更佔據空間
3)Memory 使用內存中的內容來建立表,訪問速度很是快,使用哈希索引。可是一旦服務關閉,表中的數據就會丟失。
4)Merge 是一組MyISAM表的組合,這些表必須結構徹底相同,merge自己沒有數據。對merge的查詢、更新、刪除實際是對MyISAM的修改。
1)InnoDB支持事務,MyISAM不支持。
2)MyISAM適合查詢以及插入爲主的應用,InnoDB適合頻繁修改以及涉及到安全性較高的應用。
3)InnoDB支持外鍵,MyISAM不支持。
4)從MySQL5.5.5之後,InnoDB是默認引擎。
5)MyISAM支持全文類型索引,而InnoDB不支持全文索引。
6)InnoDB中不保存表的總行數,select count(*) from table時,InnoDB須要掃描整個表計算有多少行,但MyISAM只需簡單讀出保存好的總行數便可。注:當count(*)語句包含where條件時MyISAM也需掃描整個表。
7)對於自增加的字段,InnoDB中必須包含只有該字段的索引,可是在MyISAM表中能夠和其餘字段一塊兒創建聯合索引。
8)清空整個表時,InnoDB是一行一行的刪除,效率很是慢。MyISAM則會重建表。MyisAM使用delete語句刪除後並不會馬上清理磁盤空間,須要定時清理,命令:OPTIMIZE table dept;
9)InnoDB支持行鎖(某些狀況下仍是鎖整表,如 update table set a=1 where user like ‘%lee%’)
10)Myisam建立表生成三個文件:.frm 數據表結構 、 .myd 數據文件 、 .myi 索引文件,Innodb只生成一個 .frm文件,數據存放在ibdata1.log
如今通常都選用InnoDB,主要是MyISAM的全表鎖,讀寫串行問題,併發效率鎖表,效率低,MyISAM對於讀寫密集型應用通常是不會去選用的。
應用場景:
MyISAM不支持事務處理等高級功能,但它提供高速存儲和檢索,以及全文搜索能力。若是應用中須要執行大量的SELECT查詢,那麼MyISAM是更好的選擇。
InnoDB用於須要事務處理的應用程序,包括ACID事務支持。若是應用中須要執行大量的INSERT或UPDATE操做,則應該使用InnoDB,這樣能夠提升多用戶併發操做的性能。
CHAR和VARCHAR類型在存儲和檢索方面有所不一樣
CHAR列長度固定爲建立表時聲明的長度,長度值範圍是1到255
當CHAR值被存儲時,它們被用空格填充到特定長度,檢索CHAR值時需刪除尾隨空格。
1. 一些全表掃描的慎用,or、like、<>、distinct(排除)、not in、not exists,not null的慎用。若有必然請用正向邏輯。
2. 一些重要操做請開啓事物
3. 數據庫不擅長運算,請把你的運算放在邏輯代碼中,或者放在=號右邊。
4. Limit分頁的提醒,limit 10000,10所查詢到的結果是1到10010條,而不是你所想的10條。大量數據請記得優化。
5. Sql執行順序:
(1)FROM [left_table]
(2)ON <join_condition>
(3)<join_type> JOIN <right_table>
(4)WHERE <where_condition>
(5)GROUP BY <group_by_list>
(6)WITH <CUBE | RollUP>
(7)HAVING <having_condition>
(8)SELECT
(9)DISTINCT
(10)ORDER BY <order_by_list>
(11)<Top Num> <select list>
1)避免所有掃描,好比對null值進行篩選判讀;使用!=或<>、like、or等等都將放棄索引全表掃描
2)考慮在where及order by涉及的列上創建索引
3)使用正向邏輯(not in,not exists)
4)數據庫不擅長運算,把運算交給邏輯代碼,非要有把運算放在右邊
5)合理建表,使用合理的字段,善用非空、外鍵約束保證數據的完整性
6)索引並非越多越好,一個表最好不要超過6個,多了影響增、刪、改的性能。這個影響很大
7)多從業務邏輯方面考慮問題,合理使用中間件
8)對於數據量太大的數據分庫分表,使用中間件好比mycat
①:垂直分割(並不經常使用)
就是將一個表按照字段來分,每張表保證有相同的主鍵就好。通常來講,將經常使用字段和大字段分表來放。
優點:比沒有分表來講,提升了查詢速度,下降了查詢結果所用內存;
劣勢:沒有解決大量記錄的問題,對於單表來講隨着記錄增多,性能仍是降低很快;
②: 水平分割(重要,實際應用中使用最多)
水平分割是企業最經常使用到的,水平拆分就是大表按照記錄分爲不少子表:
水平分的規則徹底是自定義的,有如下幾種參考設計:
1 hash、自增id取模:
對某個字段進行hash來肯定建立幾張表,並根據hash結果存入不一樣的表;
2 按時間
根據業務能夠按照天、月、年來進行拆分;
3 按每一個表的固定記錄數
通常按照自增ID進行拆表,一張表的數據行到了指定的數量,就自動保存到下一張表中。好比規定一張表只能存1-1000個記錄;
4 將老數據遷移到一張歷史表
好比日誌表,通常只查詢3個月以內的數據,對於超過3個月的記錄將之遷移到歷史子表中;
什麼是物理冷備?科普一下:
(1)熱備:在數據庫運行時,直接進行備份,對運行的數據庫沒有影響。
(2)冷備:在數據庫中止運行的時候進行備份,這種備份方式最爲簡單,只須要拷貝數據庫物理文件便可。
(3)溫備:一樣是在數據庫運行的時候進行備份的,但對當前數據庫的操做會產生影響。
熱備份的缺點:
1.儘可能不要出錯,不然後果會很嚴重。
2.若是熱備份不成功,所得結果不可用於時間點的數據恢復。
3.維護的工做比較困難。
冷備份的缺點:
1.單獨使用時,只能提供到"某一時間點的上"的恢復。
2.再實施備份的全過程當中,數據庫必須是關閉狀態。
3.不能按表或按用戶恢復。
綜上,若是你不是大牛大能,物理備份仍是選擇冷備份吧,自動保存7天數據。
MyISAM支持表鎖,InnoDB支持表鎖和行鎖,默認爲行鎖
表級鎖:開銷小,加鎖快,不會出現死鎖。鎖定粒度大,發生鎖衝突的機率最高,併發量最低
行級鎖:開銷大,加鎖慢,會出現死鎖。鎖力度小,發生鎖衝突的機率小,併發度最高
咱們經常使用的操做數據庫語言SQL語句在執行的時候須要要先編譯,而後執行,而存儲過程(Stored Procedure)是一組爲了完成特定功能的SQL語句集,經編譯後存儲在數據庫中,用戶經過指定存儲過程的名字並給定參數(若是該存儲過程帶有參數)來調用執行它。
一個存儲過程是一個可編程的函數,它在數據庫中建立並保存。它能夠有SQL語句和一些特殊的控制結構組成。當但願在不一樣的應用程序或平臺上執行相同的函數,或者封裝特定功能時,存儲過程是很是有用的。數據庫中的存儲過程能夠看作是對編程中面向對象方法的模擬。它容許控制數據的訪問方式。
優勢:
(1).存儲過程加強了SQL語言的功能和靈活性。存儲過程能夠用流控制語句編寫,有很強的靈活性,能夠完成複雜的判斷和較複雜的運算。
(2).存儲過程容許標準組件是編程。存儲過程被建立後,能夠在程序中被屢次調用,而沒必要從新編寫該存儲過程的SQL語句。並且數據庫專業人員能夠隨時對存儲過程進行修改,對應用程序源代碼毫無影響。
(3).存儲過程能實現較快的執行速度。若是某一操做包含大量的Transaction-SQL代碼或分別被屢次執行,那麼存儲過程要比批處理的執行速度快不少。由於存儲過程是預編譯的。在首次運行一個存儲過程時查詢,優化器對其進行分析優化,而且給出最終被存儲在系統表中的執行計劃。而批處理的Transaction-SQL語句在每次運行時都要進行編譯和優化,速度相對要慢一些。
(4).存儲過程能過減小網絡流量。針對同一個數據庫對象的操做(如查詢、修改),若是這一操做所涉及的Transaction-SQL語句被組織程存儲過程,那麼當在客戶計算機上調用該存儲過程時,網絡中傳送的只是該調用語句,從而大大增長了網絡流量並下降了網絡負載。
(5).存儲過程可被做爲一種安全機制來充分利用。系統管理員經過執行某一存儲過程的權限進行限制,可以實現對相應的數據的訪問權限的限制,避免了非受權用戶對數據的訪問,保證了數據的安全。
truncate 和 delete只刪除數據,不刪除表結構 ,drop刪除表結構,而且釋放所佔的空間。
刪除數據的速度,drop> truncate > delete
delete屬於DML語言,須要事務管理,commit以後才能生效。drop和truncate屬於DDL語言,操做馬上生效,不可回滾。
使用場合:
當你再也不須要該表時, 用 drop;
當你仍要保留該表,但要刪除全部記錄時, 用 truncate;
當你要刪除部分記錄時(always with a where clause), 用 delete
CAP定理(CAP theorem),又被稱做布魯爾定理(Brewer's theorem),它指出對於一個分佈式計算系統來講,不可能同時知足如下三點:
一致性(Consistency) 全部節點訪問同一份最新的數據副本;
可用性(Availability) 每次請求都能獲取到非錯的響應,可是不保證獲取的數據爲最新數據;
分區容錯性(Partition tolerance) 分佈式系統在遇到任何網絡分區故障的時候,仍然可以對外提供知足一致性和可用性的服務,除非整個網絡環境都發生了故障;
CAP之間是不能共存的,咱們最多隻能知足兩個條件:
CA (Consistency + Availability):關注一致性和可用性,表明做:關係型數據庫MySQL。
CP (consistency + partition tolerance):關注一致性和分區容錯性,表明做:分佈式數據庫hadoop。
AP (availability + partition tolerance):關心可用性和分區容錯性,表明做:非關係型數據庫Redis。
BASE 理論是對 CAP 理論的延伸,核心思想是即便沒法作到強一致性(Strong Consistency,CAP 的一致性就是強一致性),但應用能夠採用適合的方式達到最終一致性(Eventual Consitency)。
基本可用(Basically Available): 基本可用是指分佈式系統在出現故障的時候,容許損失部分可用性,即保證核心可用。電商大促時,爲了應對訪問量激增,部分用戶可能會被引導到降級頁面,服務層也可能只提供降級服務。這就是損失部分可用性的體現。
軟狀態(Soft State): 軟狀態是指容許系統存在中間狀態,而該中間狀態不會影響系統總體可用性。分佈式存儲中通常一份數據至少會有三個副本,容許不一樣節點間副本同步的延時就是軟狀態的體現。MySQL Replication 的異步複製也是一種體現。
最終一致性(Eventual Consistency): 最終一致性是指系統中的全部數據副本通過必定時間後,最終可以達到一致的狀態。弱一致性和強一致性相反,最終一致性是弱一致性的一種特殊狀況。
Redis 是一個開源的使用 ANSI C 語言編寫、遵照 BSD 協議、支持網絡、可基於內存亦可持久化的日誌型、Key-Value 數據庫,並提供多種語言的 API的非關係型數據庫。
1)St ing字符串:格式: set key value
string類型是二進制安全的。意思是redis的string能夠包含任何數據。好比jpg圖片或者序列化的對象 。string類型是Redis最基本的數據類型,一個鍵最大能存儲512MB。
2)Hash(哈希)格式: hmset name key1 value1 key2 value2
Redis hash 是一個鍵值(key=>value)對集合。Redis hash是一個string類型的field和value的映射表,hash特別適合用於存儲對象。
3) lsit(列表)Redis 列表是簡單的字符串列表,按照插入順序排序。你能夠添加一個元素到列表的頭部(左邊)或者尾部(右邊)
4)set(集合)
5)zset(有序集合)
Redis zset 和 set 同樣也是string類型元素的集合,且不容許重複的成員。
不一樣的是每一個元素都會關聯一個double類型的分數。redis正是經過分數來爲集合中的成員進行從小到大的排序。
zset的成員是惟一的,但分數(score)卻能夠重複。
持久化就是把內存的數據寫到磁盤中去,防止服務宕機了內存數據丟失。
Redis 提供了兩種持久化方式:RDB(默認) 和AOF
RDB:rdb是Redis DataBase縮寫
功能核心函數rdbSave(生成RDB文件)和rdbLoad(從文件加載內存)兩個函數
AOF:Aof是Append-only file縮寫
每當執行服務器(定時)任務或者函數時flushAppendOnlyFile 函數都會被調用, 這個函數執行如下兩個工做
aof寫入保存:
WRITE:根據條件,將 aof_buf 中的緩存寫入到 AOF 文件
SAVE:根據條件,調用 fsync 或 fdatasync 函數,將 AOF 文件保存到磁盤中。
比較:
一、aof文件比rdb更新頻率高,優先使用aof還原數據。
二、aof比rdb更安全也更大
三、rdb性能比aof好
四、若是兩個都配了優先加載AOF
RESP 是redis客戶端和服務端以前使用的一種通信協議;
RESP 的特色:實現簡單、快速解析、可讀性好
1)單機版
特色:簡單
問題:一、內存容量有限 二、處理能力有限 三、沒法高可用。
2)哨兵
Redis sentinel 是一個分佈式系統中監控 redis 主從服務器,並在主服務器下線時自動進行故障轉移。其中三個特性:
監控(Monitoring): Sentinel 會不斷地檢查你的主服務器和從服務器是否運做正常。
提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 能夠經過 API 向管理員或者其餘應用程序發送通知。
自動故障遷移(Automatic failover): 當一個主服務器不能正常工做時, Sentinel 會開始一次自動故障遷移操做。
特色:一、保證高可用二、監控各個節點三、自動故障遷移
缺點:主從模式,切換須要時間丟數據,沒有解決 master 寫的壓力
3)集羣(proxy 型):
Twemproxy 是一個 Twitter 開源的一個 redis 和 memcache 快速/輕量級代理服務器; Twemproxy 是一個快速的單線程代理程序,支持 Memcached ASCII 協議和 redis 協議。
特色:一、多種 hash 算法:MD五、CRC1六、CRC3二、CRC32a、hsieh、murmur、Jenkins
二、支持失敗節點自動刪除
三、後端 Sharding 分片邏輯對業務透明,業務方的讀寫方式和操做單個 Redis 一致
缺點:增長了新的 proxy,須要維護其高可用。failover 邏輯須要本身實現,其自己不能支持故障的自動轉移可擴展性差,進行擴縮容都須要手動干預
4)集羣(直連型):從redis 3.0以後版本支持redis-cluster集羣,Redis-Cluster採用無中心結構,每一個節點保存數據和整個集羣狀態,每一個節點都和其餘全部節點鏈接。
特色:一、無中心架構(不存在哪一個節點影響性能瓶頸),少了 proxy 層。
二、數據按照 slot 存儲分佈在多個節點,節點間數據共享,可動態調整數據分佈。
三、可擴展性,可線性擴展到 1000 個節點,節點可動態添加或刪除。
四、高可用性,部分節點不可用時,集羣仍可用。經過增長 Slave 作備份數據副本
五、實現故障自動 failover,節點之間經過 gossip 協議交換狀態信息,用投票機制完成 Slave到 Master 的角色提高。
缺點:
一、資源隔離性較差,容易出現相互影響的狀況。
二、數據經過異步複製,不保證數據的強一致性
先拿setnx來爭搶鎖,搶到以後,再用expire給鎖加一個過時時間防止鎖忘記了釋放。
set指令有很是複雜的參數,這個應該是能夠同時把setnx和expire合成一條指令來用的!
通常使用list結構做爲隊列,rpush生產消息,lpop消費消息。當lpop沒有消息的時候,要適當sleep一會再重試。
缺點:在消費者下線的狀況下,生產的消息會丟失,得使用專業的消息隊列如rabbitmq等。
使用pub/sub主題訂閱者模式,能夠實現1:N的消息隊列。
通常的緩存系統,都是按照key去緩存查詢,若是不存在對應的value,就應該去後端系統查找(好比DB)。一些惡意的請求會故意查詢不存在的key,請求量很大,就會對後端系統形成很大的壓力。這就叫作緩存穿透。
如何避免:
1:對查詢結果爲空的狀況也進行緩存,緩存時間設置短一點,或者該key對應的數據insert了以後清理緩存。
2:對必定不存在的key進行過濾。能夠把全部的可能存在的key放到一個大的Bitmap中,查詢時經過該bitmap過濾。
緩存雪崩:當緩存服務器重啓或者大量緩存集中在某一個時間段失效,這樣在失效的時候,會給後端系統帶來很大壓力。致使系統崩潰。
如何避免:
1:在緩存失效後,經過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。好比對某個key只容許一個線程查詢數據和寫緩存,其餘線程等待。
2:作二級緩存,A1爲原始緩存,A2爲拷貝緩存,A1失效時,能夠訪問A2,A1緩存失效時間設置爲短時間,A2設置爲長期
3:不一樣的key,設置不一樣的過時時間,讓緩存失效的時間點儘可能均勻。
JAVA_HOME=JDK 的根目錄
CATALINA_HOME=tomcat 的根目錄
CATALINA-HOME\conf\server.xml:能夠配置tomcat 的端口,能夠配置tomcat 中下鏈接
池。
CATALINA-HOME\common\lib:存放公用的類包
jsp:include:在運行時調用另外一個頁面,變量是能夠重複的。
<%@include file=」」%>:在轉譯時合在一塊兒,會成爲同一個類,變量不能夠重複。
重定向是客戶端行爲,轉發是服務器端行爲
重定向時服務器產生兩次請求,轉發產生一次請求,重定向時能夠轉發到項目之外的任何網址,轉發只能在當前項目裏轉發
重定向會致使request對象信息丟失。轉發則不會
轉發的url不會變,request.getRequestDispatch()。forward()
重定向的url會改變,response.getRedirect();
Servlet
GenericServlet
HttpServlet
自定義
extends HttpServlet 並覆蓋doPost 或doGet 方法
在web.xml 中進行部署
Init
屢次執行doGet 或doPost
destroy
對
腳本
<%%> <%=%> <%!%> <%----%>
指令
<%@page contentType=」text/html;charset=utf-8」 language=」java」
import=」」%>
<%@include file=」」%>
<%@taglib uri=」」 prefix=」」%>
動做:
<jsp:useBean class=」」 id=」」 scope=」」> 在scope 中若是沒有
實例化一個對象,若是有直接用之前的。
<jsp:getProperty name=」」 property=」」> 向一個bean 中設置屬性
值
<jsp:forward > jsp 頁的轉發
<jsp:include page=」」> 導入一個jsp 頁面
JSP一共有9個內置對象:request、response、session、application、out、pagecontext、config、page、exception。
一、Request request 表示HttpServletRequest 對象。取客戶端表單域信息及cookie,header, 和session
二、response 表示HttpServletResponse 對象,對客戶端的響應返回文本、寫cookies。
三、out 向客戶端打印html 文本.
四、pageContext :當前jsp 頁面的上下文環境,能夠獲得session、request、application等內置對象,在自定義標籤中使用的不少。
五、session 表示一個請求的javax.servlet.http.HttpSession 對象。Session 一個用戶多個頁面共享同一變量。
六、applicaton 表示一個javax.servle.ServletContext 對象。存放容器級
的變量。
七、config 表示一個javax.servlet.ServletConfig 對象。該對象用於存取servlet實例的初始化參數。
八、page 表示從該頁面產生的一個servlet 實例
九、exception:異常,當iserrorpage=true
1).隱藏表單域:<input type="hidden">,很是適合步須要大量數據存儲的會話應用。
2).URL 重寫:URL 能夠在後面附加參數,和服務器的請求一塊兒發送,這些參數爲名字/值對。
3).Cookie:一個 Cookie 是一個小的,已命名數據元素。服務器使用 SET-Cookie 頭標將它做爲 HTTP響應的一部分傳送到客戶端,客戶端被請求保存 Cookie 值,在對同一服務器的後續請求使用一個Cookie 頭標將之返回到服務器。與其它技術比較,Cookie 的一個優勢是在瀏覽器會話結束後,甚至在客戶端計算機重啓後它仍能夠保留其值
4).Session:使用 setAttribute(String str,Object obj)方法將對象捆綁到一個會話
頁面須要保存如下參數:(數據庫的分頁及比較)
總行數:根據sql 語句獲得總行數
每頁顯示行數:設定值
當前頁數:請求參數
頁面根據當前頁數和每頁行數計算出當前頁第一行行數,定位結果集到此行,對結果集
取出每頁顯示行數的行便可。
<@include file>:在將jsp 生成servlet 類前將兩個文件和在一塊兒,生成一個java 類,
一塊兒運行的。因此是一家子,當中的變量名不能重名。
<jsp:include page>:是兩個類,是一個調用關係,在運行時動態的調用,不是一家子,
能夠重複變量。
轉發: 保留上次的request
<jsp:forward>
actionMapping.findForWard(「」);
pageContext.forward();
request.getRequestDispacher(「a.jsp」).forward(request,response)
跳轉:不保留上次的request
Response.setRedirect(「」)
Jsp 主要在於頁面的顯示動態生成頁面,能夠與html 標記一塊兒使用,其仍是要生成爲一個servlet。
Servlet:主要是控制的處理,如調用業務層,跳轉不一樣的jsp 頁面。
Mvc
Jsp:v
Servlet:c
Request.getparameter(「」)
<%=application.getRealPath("aa.jsp") %>
Cookie:主要用在保存客戶端,其值在客戶端與服務端之間傳送,不安全,存儲的數據量有限。
Session:保存在服務端,每個session 在服務端有一個sessionID 做一個標識。存儲的數據量大,安全性高。佔用服務端的內存資源。
正常頁面中
%@page erropage=」error.jsp」%
錯誤頁面
<%@page iserrorpage=」true」%>
有一內置對象:exception
<jsp:useBean class=」」 id=」」 scope=」」/>
<%
New 類();
%>
作一個標記處理類extends TagSupport
經過tld 說明標記處理的類的前綴及後綴
在web.xml 中說明tld 文件
<taglib>
<taglib-uri>
<taglib-location>
<taglib>
在jsp 頁面是引用tld<%@taglib uri=」」 prefix=」」%>
ServletContext:容器,放置全局變量
setAtribute()
getAttribute()
ServletConfig:一個servlet 的配置
getInitParameter(」名稱」)
HttpServletRequest:封裝的全部的請求
getParameterValue(」名稱」)
getParameterValues(」稱」)
getSession();
getAttribute(」 名稱」);
getRequestDispatch(」a.jsp」).forward(request,response)
HttpServletResponse:響應
getOut();
sendRedirect(」」)
HttpSession:一個用戶多個頁面共享同一變量
setAttribute(」」,」」)
javax.servlet.*;javax.servlet.http.*;
Servlet 被服務器實例化後,容器運行其init 方法,請求到達時運行其service 方法,service 方法自動派遣運行與請求對應的doXXX 方法(doGet,doPost)等,當服務器決定將實例銷燬的時候調用其destroy 方法。
與cgi 的區別在於servlet 處理服務器進程中,它經過多線程方式運行其service 方法,一個實例能夠服務於多個請求,而且其實例通常不會銷燬,而CGI 對每一個請求都產生新的進程,服務完成後就銷燬,因此效率上低於servlet。
Jsp 頁面中的form 標籤裏的method 屬性爲get 時調用doGet(),爲post 時調用
doPost()。
在doGet 及doPost 方法前加入synchoronized
JSP:
<%@ page isThreadSafe="true"%>
setAttribute(String name,Object):設置名字爲name 的request 的參數值
getAttribute(String name):返回由name 指定的屬性值
getAttributeNames():返回request 對象全部屬性的名字集合,結果是一個枚舉的實例
getCookies():返回客戶端的全部Cookie 對象,結果是一個Cookie 數組
getCharacterEncoding():返回請求中的字符編碼方式
getContentLength():返回請求的Body 的長度
實例
getInputStream():返回請求的輸入流,用於得到請求中的數據
getMethod():得到客戶端向服務器端傳送數據的方法
getParameter(String name):得到客戶端傳送給服務器端的有name 指定的參數
值
getParameterNames():得到客戶端傳送給服務器端的全部參數的名字,結果是一個枚舉的實例
getParameterValues(String name):得到有name 指定的參數的全部值
getProtocol():獲取客戶端向服務器端傳送數據所依據的協議名稱
getQueryString():得到查詢字符串
getRequestURI():獲取發出請求字符串的客戶端地址
getRemoteAddr():獲取客戶端的IP 地址
getRemoteHost():獲取客戶端的名字
getSession([Boolean create]):返回和請求相關Session
getServerName():獲取服務器的名字
getServletPath():獲取客戶端所請求的腳本文件的路徑
getServerPort():獲取服務器的端口號
removeAttribute(String name):刪除請求中的一個屬性
Public String translate (String str) {
String tempStr = "";
try {
tempStr = new String(str.getBytes("ISO-8859-1"), "GBK");
tempStr = tempStr.trim();
}catch (Exception e) {
System.err.println(e.getMessage());
}
return tempStr;
}
public void init(ServletConfig config)
public ServletConfig getServletConfig()
public String getServletInfo()
public void service(ServletRequest request,ServletResponse response)
public void destroy()
Servlet的執行流程也就是servlet的生命週期,當服務器啓動的時候生命週期開始,而後經過init()《啓動順序根據web.xml裏的startup-on-load來肯定加載順序》方法初始化servlet,再根據不一樣請求調用doGet或doPost方法,最後再經過destroy()方法進行銷燬。
doGet和doPost都是接受用戶請求的方法,doGet處理get請求,doPost處理post請求,doGet用於地址欄提交,doPost用於表單提交,在頁面提交數據時,get的數據大小有限制4k,post沒有限制,get請求提交的數據會在地址欄顯示,post不顯示,因此post比get安全.
會出現線程不安全問題。不管是doGet仍是doPost去調用,服務器端處理的過程都是同樣的,那麼咱們能夠把處理過程單獨寫在另一個方法handle裏,讓兩個方法都去調用handle,根據不一樣請求去調用不一樣的方法。
線程安全就是多線程操做同一個對象不會有問題,線程同步通常來保護線程安全,因此能夠在Servlet的線程裏面加上同步方法或同步塊。(Synchronized)能夠保證在同一時間只有一個線程訪問,(使用同步塊會致使性能變差,最好不去使用實例變量)
jsp的可讀性強,容易維護,而且jsp在最後會編譯成servlet
servlet容易調試
九大內置對象:
pageContext :只對當前jsp頁面有效,裏面封裝了基本的request和session的對象
Request :對當前請求進行封裝
Session :瀏覽器會話對象,瀏覽器範圍內有效
Application :應用程序對象,對整個web工程都有效
Out :頁面打印對象,在jsp頁面打印字符串
Response :返回服務器端信息給用戶
Config :單個servlet的配置對象,至關於servletConfig對象
Page :當前頁面對象,也就是this
Exception :錯誤頁面的exception對象,若是指定的是錯誤頁面,這個就是異常對象
三大指令:
Page :指令是針對當前頁面的指令
Include :用於指定如何包含另外一個頁面
Taglib :用於定義和指定自定義標籤
七大動做:
Forward,執行頁面跳轉,將請求的處理轉發到另外一個頁面
Param :用於傳遞參數
Include :用於動態引入一個jsp頁面
Plugin :用於下載javaBean或applet到客戶端執行
useBean :使用javaBean
setProperty :修改javaBean實例的屬性值
getProperty :獲取javaBean實例的屬性值
獲取頁面的元素和值有幾種方式,分別說一下
request.getParameter() 返回客戶端的請求參數與值
request.getParameterNames() 返回全部可用屬性名的枚舉
request.getParameterValues() 返回包含參數的全部值的數組
一個是服務端,一個是客戶端
Servlet是獨立於平臺和協議的服務器端的java應用程序,能夠動態生成web頁面,並採用響應--請求的模式提供web服務
javaScript是一種解釋性語言,用於向html頁面提供交互行爲,一般被直接嵌入在html頁面中
servlet是java語言編寫的web應用
js是基於html上的一種解釋語言