java全面的知识体系结构总结
??
Java知識體系
?
目的:為了更好的認識java體系
1、java基礎知識
1.1 基礎知識
1.1.1 配置環(huán)境變量
新建java_home變量(安裝目錄),值為:C:\Program Files\Java\jdk1.6.0_14;此值為JDK的安裝位置。
?
新建classpath變量(類加載路徑),值為:.;%java_home%\lib;%java_home%\lib\tools.jar
?
修改path變量(使得系統(tǒng)可以在任何路徑下識別java命令),值為:%java_home%\bin;%java_home%\jre\bin
1.1.2 訪問修飾符
?
Public:任何地方可以訪問
Private:只有自身可以訪問
Protected:同一個包和子類可以訪問
默認:只有同一個包內可以訪問
1.2 對象的清理
1.2.1認識Java的自動垃圾回收
垃圾回收是Java語言的一大特性,方便了編程,是以消耗性能為代價的。而垃圾在這里只無用的對象。而C++是需要程序員自己寫析構函數來釋放內存的,麻煩,也有可能忘記而導致內存泄露。
Java語言對內存的分配管理是通過JVM內部機制決定的。程序員可以不關心其處理。
1.2.2垃圾回收的原理和意義
Java虛擬機中有個稱之為垃圾回收器的東西,實際上這個東西也許真正不存在,或者是已經集成到JVM中了,但這無關緊要,我們仍然可以稱為為垃圾回收器。
垃圾回收器的作用是查找和回收(清理)無用的對象。以便讓JVM更有效的使用內存。
垃圾回收器的運行時間是不確定的,由JVM決定,在運行時是間歇執(zhí)行的。雖然可以通過System.gc()來強制回收垃圾,但是這個命令下達后無法保證JVM會立即響應執(zhí)行,但經驗表明,下達命令后,會在短期內執(zhí)行你的請求。JVM通常會感到內存緊缺時候去執(zhí)行垃圾回收操作。
垃圾回收過于頻繁會導致性能下降,過于稀疏會導致內存緊缺。這個JVM會將其控制到最好,不用程序員擔心。但有些程序在短期會吃掉大量內存,而這些恐怖的對象很快使用結束了,這時候也許有必要強制下達一條垃圾回命令,這是很有必要的,以便有更多可用的物理內存。
從上面了解到,沒有用的對象就是垃圾。準確的說,當沒有任何線程訪問一個對象時,該對象就符合垃圾回收的條件。
對于String,存在一個字符串池,這個不屬于本文討論的范圍,字符串池中的垃圾回收,算法和這里所討論的垃圾回收完全是兩碼事。但是不得不說的是,字符串的胡亂拼接,往往導致性能急劇下降,尤其是在龐大的循環(huán)語句中,拼接字符串就是在讓程序慢性自殺。這也是很多Java程序員容易犯的毛病。
字符串既然是池,就是為了緩沖,為了有更高的命中率,因此垃圾回收的頻率也許會比JVM對象垃圾回收器要低很多。
垃圾回收器僅僅能做的是盡可能保證可用內存的使用效率,讓可用內存得到高效的管理。程序員可以影響垃圾回收的執(zhí)行,但不能控制。
1.2.3通過編程影響垃圾回收
雖然程序員無法控制JVM的垃圾回收機制。但是可以通過編程的手段來影響,影響的方法是,讓對象符合垃圾回收條件。
分別說來有一下幾種:
1、將無用對象賦值為null.
2、重新為引用變量賦值。比如:
Person p = new Person("aaa");
p = new Person("bbb");
這樣,new Person("aaa")這個對象就是垃圾了——符合垃圾回收條件了。
3、讓相互聯系的對象稱為“島”對象
Person p1 = new Person("aaa");
Person p2 = new Person("bbb");
Person p3 = new Person("ccc");
p1=p2; p2=p3; p3=p1;
p1=null; p2=null; p3=null;
在沒有對p1、p2、p3置null之前,它們之間是一種三角戀關系。分別置null,三角戀關系依然存在,但是三個變量不在使用它們了。三個Person對象就組成了一個孤島,最后死在堆上——被垃圾回收掉。
1.2.4強制的垃圾回收System.gc()
實際上這里的強制,是程序員的意愿、建議,什么時候執(zhí)行是JVM的垃圾回收器說了算。
調用垃圾回收也不一定能保證未使用的對象一定能從內存中刪除。
唯一能保證的是,當你內存在極少的情況,垃圾回收器在程序拋出OutofMemaryException之前運行一次。
?
1.3 集合
?
1.4 文件流
1.4.1輸出字節(jié)流
?
1.4.2 輸入字節(jié)流
?
1.4.3 輸入輸出字符流
?
1.5 網絡
1.5.1 TCP和UDP的區(qū)別
TCP是面向連接的通信協(xié)議,TCP提供兩臺計算機之間的可靠的無差別錯的數據傳輸。
UDP是無連接通信協(xié)議,UDP不保證可靠的數據的傳輸,但能夠向若干個目標發(fā)送數據,接受發(fā)自若干個源的數據。
1.6 多線程
1.6.1 實現多線程
實現多線程:繼承自Thread類,可以重寫run()方法去覆蓋去Thread中的run()方法;實現Runnable接口并實現它的run()方法。
線程的優(yōu)先級代表該線程的重要程度(不是絕對的),當有多個線程同時處于可執(zhí)行狀態(tài)并等待獲得 CPU 時間時,線程調度系統(tǒng)根據各個線程的優(yōu)先級來決定給誰分配 CPU 時間,優(yōu)先級高的線程有更大的機會獲得 CPU 時間,優(yōu)先級低的線程也不是沒有機會,只是機會要小一些罷了。
?
?
1.6.2 多線程方法的解釋和區(qū)別
1.start()是啟動一個線程。
2.join()是直到執(zhí)行完(或強制執(zhí)行一段時間)當前的線程后才往下執(zhí)行主線程或其他的線程
3.stop()是停止當前的線程。
?
阻塞線程比較多
sleep() 方法:sleep() 允許 指定以毫秒為單位的一段時間作為參數,它使得線程在指定的時間內進入阻塞狀態(tài),不能得到CPU 時間,指定的時間一過,線程重新進入可執(zhí)行狀態(tài)。可能給其他線程執(zhí)行的機會(自私,睡著了,不釋放鎖,時間到了才放鎖)
suspend() 和 resume() 方法:兩個方法配套使用,suspend()使得線程進入阻塞狀態(tài),并且不會自動恢復,必須其對應的resume() 被調用,才能使得線程重新進入可執(zhí)行狀態(tài)。
yield() 方法:yield() 使得線程放棄當前分得的 CPU 時間,但是不使線程阻塞,即線程仍處于可執(zhí)行狀態(tài),隨時可能再次分得 CPU 時間。調用 yield() 的效果等價于調度程序認為該線程已執(zhí)行了足夠的時間從而轉到另一個線程。不過yield()只能使同等級別的線程獲取執(zhí)行的機會(公平競爭,釋放大家再次選舉)。而sleep(1000)使同級別或不同級別的都有可能。
wait() 和 notify() 和notifyAll()方法是Object中定義的方法:
必須在synchronized代碼塊中使用,在synchronized代碼被執(zhí)行期間,線程可以調用對象的wait()方法,釋放對象的鎖標志,進入等待的狀態(tài),并且可以調用notify()或者notifyAll()方法通知正在等待的其他線程。notify()通知的是等待隊列中的第一個線程,notifyAll()通知的是等待隊列中的所有數量。
幾個方法配套使用,wait() 使得線程進入阻塞狀態(tài),它有兩種形式,一種允許 指定以毫秒為單位的一段時間作為參數,另一種沒有參數,前者當對應的 notify() 被調用或者超出指定時間時線程重新進入可執(zhí)行狀態(tài),后者則必須對應的 notify() 被調用。
1.6.3 wait和sleep的區(qū)別
wait()在object類里定義;sleep()在Thread類里定義。
wait()方法只能放在同步方法或同步塊中,表示資源同步時,線程需要等待。
sleep()方法可放在任何位置,表示當前線程睡眠。
wait()方法會釋放對象鎖;sleep()不會釋放對象鎖。
wait()方法要等待喚醒之后,線程才會繼續(xù)執(zhí)行。
sleep()則是休眠一段時間,線程自動恢復執(zhí)行.
sleep()必須捕獲異常,而wait(),notify()和notifyAll()不需要捕獲異常
1.6.4 notify()和notifyAll()的區(qū)別
notify() 方法導致解除阻塞的線程是從因調用該對象的 wait() 方法而阻塞的線程中隨機選取的,我們無法預料哪一個線程將會被選擇,所以編程時要特別小心,避免因這種不確定性而產生問題。
notifyAll() 方法將把因調用該對象的 wait() 方法而阻塞的所有線程一次性全部解除阻塞。當然,只有獲得鎖的那一個線程才能進入可執(zhí)行狀態(tài)。
1.6.5 run和start的區(qū)別
run()方法:在本線程內調用該Runnable對象的run()方法,可以重復多次調用;
start()方法:啟動一個線程,調用該Runnable對象的run()方法,不能多次啟動一個線程;
?
start()方法是啟動(即開辟)一個線程的方法,因此線程的啟動必須通過此方法,
而run()方法,只是Thread類的一個方法,它本身并不能開辟線程。
1.7 異常
?????? 運行時異常和Error是catch不了的。
?????? throw和throws的區(qū)別
throw是拋出一個具體的異常類,產生一個異常。
throws則是在方法名后標出該方法會產生何種異常需要方法的使用者捕獲并處理。
自定義異常必須繼承Exception類。
1.8 格式化
?????? 略
1.9 數字運算
?????? 略
1.10 正則表達式
1.10.1次數限定符
* 0次或多次
+ 至少1次
? 0或1次
{n} 指定n次
{n,} 至少n次
{n,m} 匹配n-m次
2、JAVA面向對象的基礎知識
2.1 面向對象的三個特征
2.1.1 封裝
屬性是私有,方法的公開的。
自己的數據和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。
2.1.2 繼承
它可以使用現有類的所有功能,并在無需重新編寫原來的類的情況下對這些功能進行擴展。
2.1.3 多態(tài)
實現多態(tài)有2種方式:靜態(tài)多態(tài)(編譯時的多態(tài),在同一個類中)和動態(tài)多態(tài)(一個對象可以有多種類型)。
是允許你將父對象設置成為和一個或更多的他的子對象相等的技術,賦值之后,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作。
一句話:允許將子類對象賦值給父類的引用或父類指向子類的對象。
2.1.4 總結
封裝可以隱藏實現細節(jié),使得代碼模塊化。
繼承可以擴展已存在的代碼模塊(類)。
封裝和繼承屬于代碼重用。
多態(tài)是為了接口重用。
?
?
2.1.5 繼承、聚合、組合、關聯的區(qū)別
繼承很好理解,下圖表示(實線):
?
實現也很好理解,下圖表示(虛線):
?
依賴(代碼中通常表示的是局部變量、方法參數、返回值),下圖表示:
?
關聯(代碼中通常表示的類的屬性),下圖表示:
?
聚合(關聯的一種,此時整體與部分之間是可分離的,他們可以具有各自的生命周期,部分可以屬于多個整體對象,也可以為多個整體對象共享;has-a,空心菱形),下圖表示
?
組合(關聯的一種,表示更強的關系,整體與部分是不可分的,整體的生命周期結束也就意味著部分的生命周期結束,contains-a,實心菱形),下圖表示
?
2.2 抽象、接口定義及區(qū)別
抽象類里面可以有非抽象方法
但接口里只能有抽象方法
聲明方法的存在而不去實現它的類被叫做抽像類(abstract class),它用于要創(chuàng)建一個體現某些基本行為的類,并為該類聲明方法,但不能在該類中實現該類的情況。不能創(chuàng)建abstract 類的實例。然而可以創(chuàng)建一個變量,其類型是一個抽像類,并讓它指向具體子類的一個實例。不能有抽像構造函數或抽像靜態(tài)方法。Abstract 類的子類為它們父類中的所有抽像方法提供實現,否則它們也是抽像類為。取而代之,在子類中實現該方法。知道其行為的其它類可以在類中實現這些方法。
?
接口(interface)是抽像類的變體。在接口中,所有方法都是抽像的。多繼承性可通過實現這樣的接口而獲得。接口中的所有方法都是抽像的,沒有一個有程序體。接口只可以定義static final成員變量。接口的實現與子類相似,除了該實現類不能從接口定義中繼承行為。當類實現特殊接口時,它定義(即將程序體給予)所有這種接口的方法。然后,它可以在實現了該接口的類的任何對像上調用接口的方法。由于有抽像類,它允許使用接口名作為引用變量的類型。通常的動態(tài)聯編將生效。引用可以轉換到接口類型或從接口類型轉換,instanceof 運算符可以用來決定某對象的類是否實現了接口。
?
2.3 匿名類、內部類、匿名內部類
在一個類中定義另外一個類,這個類就叫做內部類或內置類 (inner class) 。
內部類分為成員內部類、靜態(tài)嵌套類、方法內部類、匿名內部類。
內部類仍然是一個獨立的類,在編譯之后會內部類會被編譯成獨立的.class文件,但是前面冠以外部類的類命和$符號。內部類不能用普通的方式訪問。內部類是外部類的一個成員,因此內部類可以自由地訪問外部類的成員變量,無論是否是private的。
我們?yōu)槭裁词褂脙炔款?#xff1f;
A、在內部類(inner class)中,可以隨意的訪問外部類的成員,這可以讓我們更好地組織管理我們的代碼,增強代碼的可讀性。
B、內部類可以用于創(chuàng)建適配器類,適配器類是用于實現接口的類。使用內部類來實現接口,可以更好地定位與接口關聯的方法在代碼中的位置。
C、內部類的更多用法(匿名inner class實現一個接口,不過切記最后那個分號;實現繼承和接口實現時出現同名方法的問題;實現多重繼承的功能)
?
?
2.4 反射
這種動態(tài)的獲取信息及動態(tài)調用方法的機制在Java中稱為“反射”(reflection)。
Reflection 是Java被視為動態(tài)(或準動態(tài))語言的一個關鍵性質。
在JDK中,主要由以下類來實現Java反射機制,這些類都位于java.lang.reflect包中:
Class類:代表一個類;
Field 類:代表類的成員變量(成員變量也稱為類的屬性);
Method類:代表類的方法;
Constructor 類:代表類的構造方法;
Array類:提供了動態(tài)創(chuàng)建數組,以及訪問數組的元素的靜態(tài)方法;
在java.lang.Object 類中定義了getClass()方法,因此對于任意一個Java對象,都可以通過此方法獲得對象的類型。Class類是Reflection API 中的核心類,它有以下方法:
getName():獲得類的完整名字;
getFields():獲得類的public類型的屬性(包括繼承的類的public屬性);
getDeclaredFields():獲得類的所有屬性;
getMethods():獲得類的public類型的方法; (包括繼承的類的public方法);
getDeclaredMethods():獲得類的所有方法;
getMethod(String name, Class[] parameterTypes):獲得類的特定方法,name參數指定方法的名字,parameterTypes 參數指定方法的參數類型;
getConstructors():獲得類的public類型的構造方法;
getConstructor(Class[] parameterTypes):獲得類的特定構造方法,parameterTypes 參數指定構造方法的參數類型;
newInstance():通過類的不帶參數的構造方法創(chuàng)建這個類的一個對象;
通過默認構造方法創(chuàng)建一個新對象:
Object objectCopy=classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
以上代碼先調用Class類的getConstructor()方法獲得一個Constructor 對象,它代表默認的構造方法,然后調用Constructor對象的newInstance()方法構造一個實例。
獲得對象的所有屬性:
Field fields[]=classType.getDeclaredFields();
Class 類的getDeclaredFields()方法返回類的所有屬性,包括public、protected、默認和private訪問級別的屬性。
?
Java允許我們從多種途徑為一個class生成對應的Class object
(一)運用getClass()方法
(二)運用Class.getSuperclass()方法
(三)運用靜態(tài)方法Class.forName(),這個最常用
(四)運用.class語法
(五)運用原始包裝類的TYPE方法
?
2.5 淺復制和深復制
淺負責也叫淺克隆,深復制也叫深克隆。
克隆一般通過實現Cloneable中的clone方法來實現淺克隆和深克隆,但是深克隆有一個問題,如果引用對象有很多,或者說引用套引用很多重,那么太麻煩了。
業(yè)界常用的方法是使用串行化然后反串行化的方法來實現深克隆。由于串行化后,對象寫到流中,所有引用的對象都包含進來了,所以反串行化后,等于生成了一個完全克隆的對象。絕! 這個方法的要求是對象(包括被引用對象)必須事先了Serializable接口,否則就要用transient關鍵字將其排除在復制過程中。
3、UML相關知識
3.1軟件工程的生命周期
3.1.1 軟件工程的生命周期
需求捕獲、系統(tǒng)分析與設計、系統(tǒng)實現、測試、維護
3.2.UML(Unified Modeling Language)概述
?
3.3 UML組成
視圖(View)是一個或多個圖組成的對系統(tǒng)某個角度的抽象
圖(Diagram)是模型元素集的圖形表示
模型元素(Model Element)代表面向對象中的類、對象、接口、消息和關系的概念
通用機制(General Mechanism)用于表示其他信息,如注釋、模型元素的語義等
3.4視圖
視圖由圖組成,UML提供9種不同的視圖,其中視圖的包括
用例視圖(強調系統(tǒng)功能)也稱用戶模型視圖
用例圖
邏輯視圖(展現系統(tǒng)的靜態(tài)或結構組成特征)也稱為結構模型視圖或靜態(tài)視圖
類圖、對象圖
并發(fā)視圖(體現系統(tǒng)的動態(tài)或行為特征)也稱為行為模型視圖或動態(tài)視圖
時序圖、協(xié)作圖、狀態(tài)圖、活動圖
組件視圖(體現系統(tǒng)實現的結構和行為特征)也成為實現模型視圖
組件圖
配置視圖(體現系統(tǒng)實現的環(huán)境的結構和行為特征)也稱環(huán)境模型視圖或物理視圖
配置圖
3.5靜態(tài)建模機制和動態(tài)建模機制
UML內容歸納為2大類:靜態(tài)建模機制和動態(tài)建模機制
靜態(tài)建模機制包括用例圖、類圖、對象圖、組件圖、配置圖、包等
動態(tài)建模機制包括時序圖、協(xié)作圖、狀態(tài)圖、活動圖、消息等
3.6 UML用來描述模型內容的有3種:事物、關系、圖(靜態(tài)視圖和動態(tài)視圖)
?
主要說說事物和關系
事物包括如下
結構事物:用例(橢圓)、類(矩形)、接口(圓心)、協(xié)作(虛橢圓)、活動類(粗線矩形)、組件、節(jié)點(資源:電腦)
行為事物:交互(通常畫成帶箭頭的信息)、狀態(tài)機(對象的一個或多個狀態(tài)的集合)
組織事物:包
輔助事物:注釋
關系:關聯、依賴、泛化、實現
3.7 類與類關系
類(矩形:名稱、屬性、操作、職責)
其中表示+、-、#是public、private、protected
關系
依賴(有方向的虛線):使用依賴、抽象依賴、授權依賴、綁定依賴
泛化(父類和子類的關系):描述了類之間的“is a kind of ”的關系,用子類指向父類的空心三角形箭頭(實線)表示該關系。泛
化使得多態(tài)成為可能。
關聯:描述一組具有相同結構特征、行為特征、關系和語義的鏈接。
關聯的修飾有:名稱(描述關系的性質)、角色(職責)、多重性(0..n)、聚合(整體和部分,即has a的關系)、
組合(是更強的關系,是另外一種聚合,整體有管理部分特有的職責并且有一致的生命周期)等。
實現:實現規(guī)格說明和其實現間的關系。它表示不繼承結構而只繼承行為。大多數情況下,實現關系用來規(guī)定接口和實現接口的類或
組件之間的關系。(帶空心的箭頭表示,線是虛線)
3.8類圖
描述類、接口、協(xié)作以及它們之間關系的圖。
類圖包括7個元素:類、接口、協(xié)作、依賴關系、泛化關系、實現關系以及關聯關系
類圖的作用:對系統(tǒng)的詞匯建模、對簡單的協(xié)作建模、對邏輯數據庫模式建模
3.9對象圖
表示某一刻一組對象以及它們之間關系的圖
3.10包圖(略)
3.11用例視圖
?
用例(Use Case):對一個系統(tǒng)或一個應用的一種單一的使用方式所作的描述。
參與者(Actor):系統(tǒng)外部的一個實體(可以說任何事物或人)
參與者之間的關系(泛化關系、包含關系、擴展關系)
?
3.12時序圖
描述對象之間傳遞消息的時間順序,他用來表示用例中的行為順序,是強調消息時間的交互圖
包括4個元素:對象、生命線、激活、消息
?
3.13協(xié)作圖
強調參與交互的各對象結構的信息。協(xié)作圖是一種類圖。
協(xié)作圖中包含3個元素:對象、鏈、消息。
如圖:
?
3.14狀態(tài)圖
?
通過類對象的生命周期建立模型來描述對象隨時間變化的動態(tài)行為。
它包括:狀態(tài)和轉換
注意:初始狀態(tài):實圓心、終止狀態(tài):半實圓心。
狀態(tài)機、狀態(tài)、轉化
其中狀態(tài)包括:名字、入口/出口動作、內部轉換、延遲事件、子狀態(tài)。
轉換包括:源狀態(tài)、目標狀態(tài)、出發(fā)事件、監(jiān)護條件、動作
?
3.15活動圖
描述一個過程或操作的步驟。描述狀態(tài)外,更突出活動
動作狀態(tài)、活動狀態(tài)、動作流、分支、分叉和匯合、泳道、對象流。
?
3.16組件圖
描述軟件組件及組件之間的關系。
包括:組件、接口、關系(依賴、泛化、關聯、實現)。
?
3.17配置圖
顯示軟件系統(tǒng)運行的物理硬件。
包括節(jié)點(單個物理對象)、組件和關系(依賴和關聯)
??????
4、熟悉LINUX
(略)
5、SSH框架的配置及相關知識
5.1 MVC
5.1.1 簡介
MVC模式的目的就是實現Web系統(tǒng)的職能分工。 Model層實現系統(tǒng)中的業(yè)務邏輯,通常可以用JavaBean或EJB來實現。 View層用于與用戶的交互,通常用JSP來實現。 Controller層是Model與View之間溝通的橋梁,它可以分派用戶的請求并選擇恰當的視圖以用于顯示,同時它也可以解釋用戶的輸入并將它們映射為模型層可執(zhí)行的操作。
5.1.2 MVC的優(yōu)缺點
優(yōu)點:低耦合、高可復用性和可適用性、較低的生命周期成本、快速部署、可維護性、有利于軟件工程化管理。
缺點:原理較復雜花費時間思考、程序分成三個部分需要管理更多的文件。
5.1.3 MVC的現有框架
Struts: Apache的,最流行的MVC組件
Struts2 :Apache用Struts 和 WebWork的組合出來的新產品,目前上升勢頭強勁
WebWork: 這個可是老牌的MVC組件,后來組合成了Struts2, 不過自身仍在發(fā)展
Spring MVC:SpringFramework自己整合自己Spring的優(yōu)勢推出的MVC組件,用戶也不少。
JSF: 這個是一個規(guī)范,Sun的和 Apache的都有各自的實現。用戶量很大,被眾多IDE支持。
5.1.4 Model1和Model2
Model1是將業(yè)務、控制、視圖都放在jsp頁面、Model2是由業(yè)務(javaBean)、控制(ActionServlet)、視圖(Jsp)組成。
5.2 Struts
5.2.1簡介
Struts 2是Struts的下一代產品,是在 struts 和WebWork的技術基礎上進行了合并的全新的Struts 2框架。其全新的Struts 2的體系結構與Struts 1的體系結構的差別巨大。Struts 2以WebWork為核心,采用攔截器的機制來處理用戶的請求,這樣的設計也使得業(yè)務邏輯控制器能夠與Servlet API完全脫離開,所以Struts 2可以理解為WebWork的更新產品。雖然從Struts 1到Struts 2有著太大的變化,但是相對于WebWork,Struts 2只有很小的變化。
?
目的:是為了幫助我們減少在運用MVC設計模型來開發(fā)Web應用的時間。
?
Struts2的體系與Struts1體系的差別非常大,因為Struts2使用了WebWork的設計核心,而不是Struts1的設計核心。Struts2中大量使用攔截器來處理用戶的請求,從而允許用戶的業(yè)務邏輯控制器與Servlet API分離。
Struts2框架的大概處理流程如下:
1、加載類(FilterDispatcher)
2、讀取配置(struts配置文件中的Action)
3、派發(fā)請求(客戶端發(fā)送請求)
4、調用Action(FilterDispatcher從struts配置文件中讀取與之相對應的Action )
5、啟用攔截器(WebWork攔截器鏈自動對請求應用通用功能,如驗證)
6、處理業(yè)務(回調Action的execute()方法)
7、返回響應(通過execute方法將信息返回到FilterDispatcher)
8、查找響應(FilterDispatcher根據配置查找響應的是什么信息如:SUCCESS、ERROER,將跳轉到哪個jsp頁面)
9、響應用戶(jsp--->客戶瀏覽器端顯示)
10、struts2標簽庫(相比struts1的標簽庫,struts2是大大加強了,對數據的操作功能很強大)。
?
5.2.2 Struts2和Struts1的對比
在Action的實現方面:Struts1要求必須統(tǒng)一擴展自Action類,而Struts2中可以是一個普通的POJO。
線程模型方面:Struts1的Action工作在單例模式,一個Action的實例處理所有的請求。Struts2的Action是一個請求對應一個實例。沒有線程安全方面的問題。
Servlet依賴方面:Struts1的Action依賴于Servlet API,比如Action的execute方法的參數就包括request和response對象。這使程序難于測試。Struts2中的Action不再依賴于Servlet API,有利于測試,并且實現TDD。
封裝請求參數:Struts1中強制使用ActionForm對象封裝請求的參數。Struts2可以選擇使用POJO類來封裝請求的參數,或者直接使用Action的屬性。
表達式語言方面:Struts1中整合了EL,但是EL對集合和索引的支持不強,Struts2整合了OGNL(Object Graph NavigationLanguage)。
綁定值到視圖技術:Struts1使用標準的JSP,Struts2使用“ValueStack”技術。
參見文檔:http://www.blogjava.net/freeman1984/archive/2011/02/16/344447.html
?
類型轉換:Struts1中的ActionForm基本使用String類型的屬性。Struts2中使用OGNL進行轉換,可以更方便的使用。
數據校驗:Struts1中支持覆蓋validate方法或者使用Validator框架。Struts2支持重寫validate方法或者使用XWork的驗證框架。
Action執(zhí)行控制的對比:Struts1支持每一個模塊對應一個請求處理,但是模塊中的所有Action必須共享相同的生命周期。Struts2支持通過攔截器堆棧為每一個Action創(chuàng)建不同的生命周期。
5.2.3 在web.xml中的配置
???? <filter>
???????? <filter-name>action2</filter-name>
???????? <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
? ?? <filter-mapping>
???????? <filter-name>action2</filter-name>
???????? <url-pattern>*.action</url-pattern>
</filter-mapping>
?
5.3 Hibernate
5.3.1 簡介
Hibernate是一個對象關系映射框架,它對JDBC進行了非常輕量的對象封裝,使得java程序員可以隨心所欲地使用對象編程思維來操縱數據庫。
?
5.3.2 Hibernate主鍵介紹
Assigned(依賴用戶)
Assigned方式由用戶生成主鍵值,并且要在save()之前指定否則會拋出異常
特點:主鍵的生成值完全由用戶決定,與底層數據庫無關。用戶需要維護主鍵值,在調用session.save()之前要指定主鍵值。
Hilo(依賴數據表)
Hilo使用高低位算法生成主鍵,高低位算法使用一個高位值和一個低位值,然后把算法得到的兩個值拼接起來作為數據庫中的唯一主鍵。Hilo方式需要額外的數據庫表和字段提供高位值來源。默認情況下使用的表是 hibernate_unique_key,默認字段叫作next_hi。next_hi必須有一條記錄否則會出現錯誤。
特點:需要額外的數據庫表的支持,能保證同一個數據庫中主鍵的唯一性 ,但不能保證多個數據庫之間主鍵的唯一性。Hilo主鍵生成方式由Hibernate 維護,所以Hilo方式與底層數據庫無關,但不應該手動修改hi/lo算法使用的表的值,否則會引起主鍵重復的異常。
Increment(依賴數據Sequence)
Increment方式對主鍵值采取自動增長的方式生成新的主鍵值,但要求底層數據庫的支持Sequence。如Oracle,DB2等。需要在映射文件xxx.hbm.xml中加入Increment標志符的設置。
這個是由Hibernate在內存中生成主鍵,每次增量為1,不依賴于底層的數據庫,因此所有的數據庫都可以使用,但問題也隨之而來,由于是Hibernate生成的,所以只能有一個Hibernate應用進程訪問數據庫,否則就會產生主鍵沖突,不能在集群情況下使用插入數據的時候hibernate會給主鍵添加一個自增的主鍵,但是一個hibernate實例就維護一個計數器,所以在多個實例運行的時候不能使用這個方法。
特點:由Hibernate本身維護,適用于所有的數據庫,不適合多進程并發(fā)更新數據庫,適合單一進程訪問數據庫。不能用于群集環(huán)境。
Identity(自增)
Identity當時根據底層數據庫,來支持自動增長,不同的數據庫用不同的主鍵增長方式。
特點:與底層數據庫有關,要求數據庫支持Identity,如MySQl中是auto_increment, SQL Server 中是Identity,支持的數據庫有MySql、SQL Server、DB2、Sybase和HypersonicSQL。 Identity無需Hibernate和用戶的干涉,使用較為方便,但不便于在不同的數據庫之間移植程序。
Sequence(依賴數據Sequence)
Sequence需要底層數據庫支持Sequence方式,例如Oracle數據庫等
特點:需要底層數據庫的支持序列,支持序列的數據庫有DB2、PostgreSql、Oracle、SAPDb等在不同數據庫之間移植程序,特別從支持序列的數據庫移植到不支持序列的數據庫需要修改配置文件
Native(依賴具體的數據庫)
Native主鍵生成方式會根據不同的底層數據庫自動選擇Identity、Sequence、Hilo主鍵生成方式
特點:根據不同的底層數據庫采用不同的主鍵生成方式。由于Hibernate會根據底層數據庫采用不同的映射方式,因此便于程序移植,項目中如果用到多個數據庫時,可以使用這種方式。
UUID(依賴算法)
UUID使用128位UUID算法生成主鍵,能夠保證網絡環(huán)境下的主鍵唯一性,也就能夠保證在不同數據庫及不同服務器下主鍵的唯一性。
特點;能夠保證數據庫中的主鍵唯一性,生成的主鍵占用比較多的存貯空間
Foreign GUID(外鍵)
Foreign用于一對一關系中,使用外部表的字段作為主鍵。
5.3.3 緩存管理
Hibernate 中提供了兩級Cache,第一級別的緩存是Session級別的緩存,它是屬于事務范圍的緩存。這一級別的緩存由hibernate管理的,一般情況下無需進行干預;第二級別的緩存是SessionFactory級別的緩存,它是屬于進程范圍或群集范圍的緩存。這一級別的緩存可以進行配置和更改,并且可以動態(tài)加載和卸載。 Hibernate還為查詢結果提供了一個查詢緩存,它依賴于第二級緩存。
一級緩存的管理
當應用程序調用Session的save()、update()、saveOrUpdate()、get()或load(),以及調用查詢接口的 list()、iterate()或filter()方法時,如果在Session緩存中還不存在相應的對象,Hibernate就會把該對象加入到第一級緩存中。當清理緩存時,Hibernate會根據緩存中對象的狀態(tài)變化來同步更新數據庫。 Session為應用程序提供了兩個管理緩存的方法: evict(Object obj):從緩存中清除參數指定的持久化對象。 clear():清空緩存中所有持久化對象。
二級緩存的管理
Hibernate的二級緩存策略的一般過程如下:
1) 條件查詢的時候,總是發(fā)出一條select * from table_name where …. (選擇所有字段)這樣的SQL語句查詢數據庫,一次獲得所有的數據對象。
2) 把獲得的所有數據對象根據ID放入到第二級緩存中。
3) 當Hibernate根據ID訪問數據對象的時候,首先從Session一級緩存中查;查不到,如果配置了二級緩存,那么從二級緩存中查;查不到,再查詢數據庫,把結果按照ID放入到緩存。
4) 刪除、更新、增加數據的時候,同時更新緩存。
Hibernate的二級緩存策略,是針對于ID查詢的緩存策略,對于條件查詢則毫無作用。為此,Hibernate提供了針對條件查詢的Query Cache。
什么樣的數據適合存放到第二級緩存中?
1 很少被修改的數據 2 不是很重要的數據,允許出現偶爾并發(fā)的數據 3 不會被并發(fā)訪問的數據 4 參考數據,指的是供應用參考的常量數據,它的實例數目有限,它的實例會被許多其他類的實例引用,實例極少或者從來不會被修改。
不適合存放到第二級緩存的數據?
1 經常被修改的數據 2 財務數據,絕對不允許出現并發(fā) 3 與其他應用共享的數據。
常用的緩存插件 Hibernater 的二級緩存是一個插件
下面是幾種常用的緩存插件:
EhCache:可作為進程范圍的緩存,存放數據的物理介質可以是內存或硬盤,對Hibernate的查詢緩存提供了支持。
OSCache:可作為進程范圍的緩存,存放數據的物理介質可以是內存或硬盤,提供了豐富的緩存數據過期策略,對Hibernate的查詢緩存提供了支持。
SwarmCache:可作為群集范圍內的緩存,但不支持Hibernate的查詢緩存。
JBossCache:可作為群集范圍內的緩存,支持事務型并發(fā)訪問策略,對Hibernate的查詢緩存提供了支持。
上述4種緩存插件的對比情況列于表9-3中。
表9-3 4種緩存插件的對比情況
| 緩 存 插 件 | 支 持 只 讀 | 支持非嚴格讀寫 | 支 持 讀 寫 | 支 持 事 務 |
| EhCache | 是 | 是 | 是 | ? |
| OSCache | 是 | 是 | 是 | ? |
| SwarmCache | 是 | 是 | ? | ? |
| JBossCache | 是 | ? | ? | 是 |
它們的提供器列于表9-4中。
表9-4 緩存策略的提供器
| 緩 存 插 件 | 提供器(Cache Providers) |
| Hashtable(只能測試時使用) | org.hibernate.cache.HashtableCacheProvider |
| EhCache | org.hibernate.cache.EhCacheProvider |
| OSCache | org.hibernate.cache.OSCacheProvider |
| SwarmCache | org.hibernate.cache.SwarmCacheProvider |
| JBossCache | org.hibernate.cache.TreeCacheProvider |
在默認情況下,Hibernate使用EhCache進行JVM級別的緩存。用戶可以通過設置Hibernate配置文件中的hibernate.cache.provider_class的屬性,指定其他的緩存策略,該緩存策略必須實現org.hibernate.cache.CacheProvider接口。
配置二級緩存的主要步驟:
1) 選擇需要使用二級緩存的持久化類,設置它的命名緩存的并發(fā)訪問策略。這是最值得認真考慮的步驟。
2) 選擇合適的緩存插件,然后編輯該插件的配置文件。
?
緩存作用范圍
事務范圍(一級緩存——Session級別)
事務存在與內存中,事務范圍內的對象都有一個對象ID(OID),它對應數據庫表中的代理主鍵(沒有實際意義僅用來標示記錄號,相對于有實際意義的自然主鍵)
進程范圍(二級緩存——SessionFactory級別)
緩存內的數據被進程中的事務共享操作數據時需運用所機制
集群范圍(二級緩存——SessionFactory級別)
一級緩存Session
減少訪問數據庫的頻率
Transaction? tx = session . beginTransaction();
//第一次
Bird? b1 = (Bird) session . get(Bird . class , new? long(1));
//第二次
Bird? b2 = (Bird) session . get(Bird . class , new? long(1));
tx . commit();
session第一次加載對象時先從緩存中查找,如沒找到在從數據庫中查找并加載到緩存中;第二次加載時直接從緩存中加載而不需再次訪問數據庫。
保證數據庫中的相關記錄與緩存中相應對象保持同步
Session緩存中的數據在提交數據庫之前進行了幾次修改,當數據提交時只執(zhí)行一次最后一次修改的update操作。
?
配置二級緩存步驟
選擇需要使用二級緩存的持久化類,設置它的二級緩存并發(fā)訪問策略(只讀,只寫,可讀可寫)。
選擇合適的緩存插件,每一種緩存插件都有自帶的配置文件,需要手動配置。
?
例如配置ehcache緩存
?
1、在Hibernate配置文件中,指定ehcache適配器
Hibernate . cfg . xml添加元素
//二級緩存存在的類
<property? name=”hibernate . cache . provider_class”>org . hibernate . cache . EhCacheProvide</Property>
/查詢時是否使用二級緩存
<property? name=”hibernate . cache . use_query_cache”>true</Property>
2、在映射文件中配置<cache>元素
XXX . hbm . xml
//指定并發(fā)訪問策略
<cache? usage=”read-write”/>
3、編寫ehcache . xml,并將此文件放在src文件夾下
eacache . xml
<?xml? version=”1.0” encoding=”UTF-8”?>
<ehcache>
?????????????????? <diskStore? path=”java . io . tempdir”/>
?????????????????? <!--
??????????????????????????? maxElementsInMemory:允許緩存可存儲的總記錄數
??????????????????????????? eternal:當前緩存是否永遠不過期
??????????????????????????? overflowToDisk:當前緩存中數據達到最大值時,是否把緩存數據寫入硬盤
??????????????????????????? timeToIdleSeconds:當前緩存最大閑置時間,超過該時間則銷毀緩存
??????????????????????????? timeToLiveSeconds:設置超時時間,當緩存創(chuàng)建后達到該時間就自動銷毀
?????????????????? -->
?????????????????? <defaultCache
??????????????????????????? maxElementsInMemory=”5”
??????????????????????????? eternal=”false”
??????????????????????????? overflowToDisk=”true”
??????????????????????????? timeToIdleSeconds=”15”
??????????????????????????? timeToLiveSeconds=”120”
?????????????????? />
</ehcache>
?
5.3.4 Hibernate映射
?????? Hibernate映射分為:內置映射和自定義映射。
?????? 使用<property>定義屬性
?????? 使用<many-to-one>配置多對一映射
?????? 使用<one-to-one>配置一對一映射(主鍵關聯和唯一外鍵關聯)
??????
5.3.5 Hibernate核心編程
?????? Hibernate的核心接口一共有5個,分別為:Session、SessionFactory、Transaction、Query和Configuration。這5個核心接口在任何開發(fā)中都會用到。通過這些接口,不僅可以對持久化對象進行存取,還能夠進行事務控制。
Session接口
Session接口負責執(zhí)行被持久化對象的CRUD操作(CRUD的任務是完成與數據庫的交流,包含了很多常見的SQL語句。)。但需要注意的是Session對象是非線程安全的。同時,Hibernate的session不同于JSP應用中的HttpSession。這里當使用session這個術語時,其實指的是Hibernate中的session,而以后會將HttpSession對象稱為用戶session。
SessionFactory接口
SessionFactory接口負責初始化Hibernate。它充當數據存儲源的代理,并負責創(chuàng)建Session對象。這里用到了工廠模式。需要注意的是SessionFactory并不是輕量級的,因為一般情況下,一個項目通常只需要一個SessionFactory就夠,當需要操作多個數據庫時,可以為每個數據庫指定一個SessionFactory。
Configuration接口
Configuration接口負責配置并啟動Hibernate,創(chuàng)建SessionFactory對象。在Hibernate的啟動的過程中,Configuration類的實例首先定位映射文檔位置、讀取配置,然后創(chuàng)建SessionFactory對象。
Transaction接口
Transaction接口負責事務相關的操作。它是可選的,開發(fā)人員也可以設計編寫自己的底層事務處理代碼。
Query和Criteria接口
Query和Criteria接口負責執(zhí)行各種數據庫查詢。它可以使用HQL語言或SQL語句兩種表達方式。
?????? 注意:Configuration實例時一個啟動期間的對象,一旦SessionFactory創(chuàng)建完成它就被丟棄。
?
5.3.6 Session的三個狀態(tài)
自由態(tài)(不曾進行持久化,未與任何Session相關聯)
持久態(tài)(僅與一個Session相關聯)
游離態(tài)(已經進行了持久化,但未與當前任何Session相關聯)
?
?
Transient(自由態(tài))狀態(tài)最大的特征是:
????????? * 在數據庫中沒有與之匹配的數據
????????? * 沒有納入session的管理
?
Persistent(持久態(tài))狀態(tài)最大的特征是:
????????? * 在數據庫中有與之匹配的數據
????????? * 納入了session的管理
????????? * 在清理緩存(臟數據檢查)的時候,會和數據庫同步
?
Detached(游離態(tài))狀態(tài)最大的特征是:
????????? * 在數據庫中有與之匹配的數據
????????? * 沒有納入session的管理
狀態(tài)轉換:
?
5.3.7 Session操作
save()方法保存對象 引發(fā)INSERT
load()方法裝載對象 如果沒有匹配的數據庫記錄,load()方法可能會拋出無法恢復的異常。
get()方法裝載對象 會立即訪問數據庫,如果沒有對象的記錄,則返回null。
flush()方法強制提交刷新。
update()方法提交游離狀態(tài)的對象。
delete()方法移除持久化對象。
refresh ()方法強制裝載對象。
?
5.3.8 Session查詢
不帶參數查詢
Query query = session.createQuery(“from User”);
?
帶參數查詢
Query query = session.createQuery(“from User where username=:username”);
Query.setLockMode(“user”,LockMode.upgrade);?? 加鎖
Query.setString(“username”,”admin”);
?
也可使用setParameterList()設置該參數
List names = new ArrayList();
names.add(“admin”);
names.add(“test”);
Query query = session.createQuery(“from User where username in(:unameList)”);
Query.setString(“unameList”,names);
還可以帶問號
Query query = session.createQuery(“from User where username=?”);
Query.setString(0,”admin”);
?
setProperties()方法:
在Hibernate中可以使用setProperties()方法,將命名參數與一個對象的屬性值綁定在一起,如下程序代碼:
Customer customer=new Customer();
customer.setName(“pansl”);
customer.setAge(80);
Query query=session.createQuery(“from Customer c where c.name=:name and c.age=:age ”);
query.setProperties(customer);
?
取得List結果集
List list =query.list();
取得迭代結果集
Iterator iter=query.iterate();
或
Iterator iter=query.list().iterator();
list()和iterator()區(qū)別:查詢機制不同
list方法僅查詢一次,查詢全部數據
iterator可能會查詢多次,首先從數據庫中檢索出所有符合條件的記錄的id字段(僅有id),然后掃描緩存,如果緩存中包含全部數據則無需再查詢數據庫,直接引用。如果緩存中不包含任何數據需要再次查詢數據庫。
大多數情況下使用list進行查詢,當對象包含大量屬性,或者要加載的大部分數據已經在緩存中,可使用iterator;
?
?
取得一個對象
Query query = session.createQuery(“from User where username=:username”);
Query.setString(“username”,”admin”);
User user = (User)query.uniqueResult();
標量查詢(查某個具體的字段或是統(tǒng)計函數等)
略
分頁查詢
Query query = session.createQuery(“from User”);
query.setFirstResult(10);//設置起始范圍,從第11數據開始取
query.setMaxResults(20);//設置結束范圍,最多能取20條數據(如果有的話)
List list =query.list();
創(chuàng)建SQL查詢
Query query = session.createSQLQuery(“select? {user.*} from User {user} where username=?”);
其他一樣(別名需要大括號括起來)
?
5.3.9面向對象的Criteria查詢
創(chuàng)建Criteria實例
Criteria criteria = session.createCriteria(User.class);
criteria.setMaxResults(50);
List users= criteria.list();
?
添加查詢條件
criteria.add(Restrictions.like(“username”,”%admin%”));
criteria.add(Restrictions.between(“ID”,1,10));
?
添加排序
criteria.add(Order.asc(“username”));
?
示例查詢
User user=new User();
user.setUsernem(“admin”);
criteria.add(Example.create(user));
?
?
5.3.10在Hibernate中實現增加(修改,刪除)操作的步驟
1、讀取并解析配置文件
Configuration? config=new? Configuration() . configure();
2、讀取并解析映射信息,并創(chuàng)建SessionFactory
SessionFactory? sessionfactory=config . buildSessionFactory();
3、打開session
this . session=sessionfactory . openSession();
4、打開一個事務(增刪改必選,查詢可選)
tran=this.session . beginTransaction();
5、持久化操作
this . session . save(login);(增加操作)
this . session . update(login);(修改操作)
this . session . dalete(login)(刪除操作)
6、提交事務
tran . commit();
7、關閉session
This . session.close();
?
5.3.11 事務
基于JTA的事物管理
JTA提供了跨Session的事物管理能力
JTA事物管理則由JTA容器實現,JTA容器對當前加入事務的眾多Connection 進行調度
JTA的事務周期可橫跨多個JDBC Connection生命周期
JTA事務是由JTA Container維護,而參與事務的Connection無需對事務管理進行干涉
?
5.3.12 Hibernate加鎖模式
LockMode.NONE : 無鎖機制
LockMode.WRITE : Hibernate在Insert和Update記錄時會自動獲取
LockMode.READ :Hibernate在讀取記錄時會自動獲取
LockMode.UPGRADE : 利用數據庫的for update子句加鎖
LockMode.UPGRADE_NOWAIT : Oracle的特定實現,利用Oracle的for update nowait子句實現加鎖
Criteria.setLockMode
Query.setLockMode
Session.lock
?
5.3.13 Session管理
Session不是線程安全的,所以讓多個線程共享一個Session發(fā)生數據沖突,所以Session需要管理
ThreadLocal模式: ThreadLocal并不是一個線程的本地實現,即他不是一個線程(Thread),而是一個線程局部變量(Thread? local? variable)。它的作用就是為每一個使用這個變量的線程都提供一個變量值的副本,并且每一個線程都可以獨立的改變自己的副本,而不會和其他線程的副本產生沖突。
openSession()和getCurrentSession()
創(chuàng)建session的方法除了有openSession()之外,getCurrentSession()也可以創(chuàng)建Session;
getCurrentSession()創(chuàng)建的Session會綁定到當前線程,而openSession()不會
getCurrentSession()創(chuàng)建的Session會在事務提交或回滾后自動關閉,而openSession()則需要手動關閉(調用Session的close()方法)
使用getCurrentSession()的方法
當使用本地事務時(JDBC事務)
需要在hibernate.cfg.xml文件的<session-factory>節(jié)點中添加
<property? name=”hibernate.current_session_context_class”>thread</property>
當使用全局事務時(JTA事務)
需要在hibernate.cfg.xml文件的<session-factory>節(jié)點中添加
<property? name=”hibernate.current_session_context_class”>jta</property>
5.3.14 關聯關系
持久化對象不通過外鍵建立對象之間的關聯關系,而是通過屬性
持久化對象之間的關聯關系的種類:一對一,一對多(多對一),多對多
持久化類之間關聯關系的方向:單向關聯,雙向關聯
?
一對多(在年級的xml中)
<set? name=”students”>
?????? <key? column=”gid”/>?? //年級???? <!—此處gid為Student表中的gid外鍵字段-->
?????? <one-to-many? class=”com . pb . hibernate . pb . Students”/>
</set>
?多對一(在學生中)??
?????? <many-to-one? name=”grade” class=”hib3.po.Grade” cascade=”save-update”>
????????????? <column? name=”gid”/>
?????? </many-to-one>
配置反轉屬性:inverse,將維護關聯關系的任務反轉,交給對方完成
inverse只能用于集合屬性中,即關聯關系中“一”的一方;反轉關聯關系給“多”的一方。
?????? 即:
<set? name=”students” inverse=“true”>
?????? <key? column=”gid”/>
?????? <one-to-many? class=”com . pb . hibernate . pb . Students”/>
</set>
?????? 一對一關聯
在People類中添加License類的屬性,在License類中添加People的屬性
People . hbm . xml中通過<one-to-one>標簽實現映射
License . hbm . xml中通過<many-to-one>標簽實現映射
?
People類???????????????????????????????????????????????????????????????????????????? License類
pid????? :int??????????????????????????????????????????????????????????????? lid?????? :int
pname?? :String????????????????????????????? 1:1??????????????????????? ldesc?????? :String
pgender? :String???????????????????????????????????????????????????????? people??? :People
license??? :License??????????????????????????????????????????????????????
People類People . hbm . xml(主動方)
<one-to-one? name=”license” class=”hib3.po.License” cascade=”all” lazy=”false”/>
注:在<one-to-one>標簽中一般吧cascade屬性值設為all,lazy屬性設為false
License類License . hbm . xml(被動方)
<many-to-one? name=”people” class=”hib3.po.People” unique=”true” lazy=”false”>
?????? <!--外鍵設置在被動方表中-->
?????? <column? name=”pid”/>
</many-to-one>
注:unique意為唯一,hibernate通過unique屬性將多對一關系限制為一對一;
?
多對多關聯關系
?
1、不創(chuàng)建中間表的持久化類,只創(chuàng)建兩端表的持久化類,在映射文件中使用<many-to-many>標簽設置映射
Student.hbm.xml
?????? <set? name=”courses” table=”sc” cascade=”save-update”>
????????????? <!-- Student與中間表發(fā)生關聯的字段是“sid”-->
????????????? <key? column=”sid”>
<!—中間表與Course類發(fā)生關聯的字段是“cid”-->
????????????? <many-to-many? class=”hib3.po.Course” column=”cid”>
?????? </set>
?Course.hbm.xml
?????? <set? name=”students” table=”sc” cascade=”save-update” inverse=“true”>
????????????? <!-- Course與中間表發(fā)生關聯的字段是“cid”-->
????????????? <key? column=”cid”>
<!—中間表與Student類發(fā)生關聯的字段是“sid”-->
????????????? <many-to-many? class=”hib3.po.Student” column=”sid”>
?????? </set>
注:在其中一方添加inverse屬性,只有一方維護關聯關系
?
2、創(chuàng)建中間表,兩端表的持久化類,針對中間表的持久化類分別和兩端表的持久化類創(chuàng)建一對多的關聯關系
?
?
5.3.15 查詢方式
分別是HQL查詢??,對象化查詢Criteria方法,動態(tài)查詢DetachedCriteria,例子查詢,sql查詢,命名查詢。?
?
HQL查詢
通過Query接口使用HQL語言進行查詢,HQL是hibernate自己的一套查詢語言,于SQL語法不同,具有跨數據庫的優(yōu)點。
對象化查詢方式
通過Criteria等接口和類進行查詢。
動態(tài)分離查詢DetachedCriteria
面向對象操作,分離業(yè)務與底層,不需要字段屬性攝入到Dao實現層
SQL查詢方式
使用原聲SQL語言進行查詢。
命名查詢方式
適用情況:萬能方法,有點像ibatis輕量級框架的操作,方便維護。? 缺點:不面向對象。基于hql和sql,有一定缺陷。
?
?????? 屬性查詢有直接查詢和通過構造方法查詢。
fetch關鍵字
用來表示家在對象時查詢語句的形式和加載時機。有3個取值:
select:加載關聯對象時通過select語句實現。默認
subselect:通過帶子查詢語句實現
join:執(zhí)行立即檢索,采用迫切左外連接檢索所有關聯對象,lazy屬性將被忽略
注:select和subselect適用于立即檢索和延遲檢索,jion僅適用于立即檢索
select和subselect決定加載關聯對象時查詢語句的形式,join決定加載時機
5.3.16 命名查詢
HQL語句混雜在代碼中會破壞代碼可讀性
Hibernate允許在影射配置文件中定義字符串形式的查詢語句,即是命名查詢。
?
命名查詢——映射配置文件
?????? <hibernate-mapping>
???????????????????? <class? name=”hib3.po.Login” table=”LOGIN”>
??????????????????????????? <!--。。。。。省略其他配置-->
???????????????????? </class>
???????????????????? <query? name=”loginUser”>
??????????????????????????? <![CDATA[
??????????????????????????? ? from Login login where login.username=:username and login.password=:password]]>
???????????????????? </query>
?????? </hibernate-mapping>
以<![CDATA[HQL]]>方式保存HQL語句
在程序中使用Session的getNamedQuery(“hql語句名”)方法獲取配置文件中的hql語句。
?
<!--設置JDBC單次批量處理數目(一般10-50)-->
<property? name=”hibernate . jdbc . batch_size”>20</property>
(Session緩存為Hibernate一級緩存,是事務范圍內的緩存;Session外置緩存是Hibernate二級緩存,是應用范圍內的緩存,即所有事物共享二級緩存。二級緩存默認關閉)
?????? <property? name=”hibernate . cache . use_second_level_cache”>false</property>
?
批量更新處理:使用可滾動結果集(ScrollableResults)
//ScrollableResults對象中存儲的是游標,但需要此對象時才會到數據庫中加載
ScrollableResults? logins = session . createQuery(“from? Login”) . scroll(ScrollMode . forward_only);
使用CallableStatement調用存儲過程
CallableStatement? cst = session . connection() . prepareCall(“{call login_insert(?,?,?)}”)
cst . setString(1,“aaa”);
cst . setString(2,“22222”);
cst . setLong (3,“21”);
cst . executeUpadte();
調用帶有返回結果集的存儲過程
Session? session = new? Configuration() . configure() . buildSessionFactory() . openSession();
Transaction? tran = session . beginTransaction();
CallableStatement? cst = session . connection() . prepareCall(“{call login_getlist(?)}”)
cst . registerOutParameter(1 , oracle . jdbc . OracleType . cursor);
cst . execute();
ResultSet? rs=(ResultSet)cst . getObject(1);
?????? while(rs.next()){
????????????? ……
}
使用命名SQL調用存儲過程
使用命名SQL的插入方法(更新功能類似)
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
5.3.17 Hibernate注解
使用注解方式來注釋類,屬性
可以省略類——表映射文件(hbm . xml文件)
?
Hibernate注解的優(yōu)勢
?????? 簡化對象關系映射的開發(fā)
?????? 通過注解方式可以自動生成數據庫表
?
使用注解進行對象映射步驟
1、為每一個實體Bean使用@Entity注解
2、使用@ID指定實體Bean的標識屬性
3、使用@Table指明當前實體Bean對應數據庫那張表
4、使用@GeneratedValue指定主鍵生成類型
5、修改Hibernate配置文件
?
5.4 Spring
5.4.1 簡介
Spring是一個開源框架,它由Rod Johnson創(chuàng)建。它是為了解決企業(yè)應用開發(fā)的復雜性而創(chuàng)建的。Spring使用基本的JavaBean來完成以前只可能由EJB完成的事情。然而,Spring的用途不僅限于服務器端的開發(fā)。從簡單性、可測試性和松耦合的角度而言,任何Java應用都可以從Spring中受益。
簡單來說,Spring是一個輕量級的控制反轉(IoC)和面向切面(AOP)的容器框架。
◆輕量——從大小與開銷兩方面而言Spring都是輕量的。完整的Spring框架可以在一個大小只有1MB多的JAR文件里發(fā)布。并且Spring所需的處理開銷也是微不足道的。此外,Spring是非侵入式的:典型地,Spring應用中的對象不依賴于Spring的特定類。
◆控制反轉——Spring通過一種稱作控制反轉(IoC)的技術促進了松耦合。當應用了IoC,一個對象依賴的其它對象會通過被動的方式傳遞進來,而不是這個對象自己創(chuàng)建或者查找依賴對象。你可以認為IoC與JNDI相反——不是對象從容器中查找依賴,而是容器在對象初始化時不等對象請求就主動將依賴傳遞給它。
◆面向切面——Spring提供了面向切面編程的豐富支持,允許通過分離應用的業(yè)務邏輯與系統(tǒng)級服務(例如審計(auditing)和事務(transaction)管理)進行內聚性的開發(fā)。應用對象只實現它們應該做的——完成業(yè)務邏輯——僅此而已。它們并不負責(甚至是意識)其它的系統(tǒng)級關注點,例如日志或事務支持。
◆容器——Spring包含并管理應用對象的配置和生命周期,在這個意義上它是一種容器,你可以配置你的每個bean如何被創(chuàng)建——基于一個可配置原型(prototype),你的bean可以創(chuàng)建一個單獨的實例或者每次需要時都生成一個新的實例——以及它們是如何相互關聯的。然而,Spring不應該被混同于傳統(tǒng)的重量級的EJB容器,它們經常是龐大與笨重的,難以使用。
◆框架——Spring可以將簡單的組件配置、組合成為復雜的應用。在Spring中,應用對象被聲明式地組合,典型地是在一個XML文件里。Spring也提供了很多基礎功能(事務管理、持久化框架集成等等),將應用邏輯的開發(fā)留給了你。
所有Spring的這些特征使你能夠編寫更干凈、更可管理、并且更易于測試的代碼。它們也為Spring中的各種模塊提供了基礎支持。
5.4.2 特點
◆方便解耦,簡化開發(fā)
通過Spring提供的IoC容器,我們可以將對象之間的依賴關系交由Spring進行控制,避免硬編碼所造成的過度程序耦合。有了Spring,用戶不必再為單實例模式類、屬性文件解析等這些很底層的需求編寫代碼,可以更專注于上層的應用。
◆AOP編程的支持
通過Spring提供的AOP功能,方便進行面向切面的編程,許多不容易用傳統(tǒng)OOP實現的功能可以通過AOP輕松應付。
◆聲明式事務的支持
在Spring中,我們可以從單調煩悶的事務管理代碼中解脫出來,通過聲明式方式靈活地進行事務的管理,提高開發(fā)效率和質量。
◆方便程序的測試
可以用非容器依賴的編程方式進行幾乎所有的測試工作,在Spring里,測試不再是昂貴的操作,而是隨手可做的事情。
◆方便集成各種優(yōu)秀框架
Spring不排斥各種優(yōu)秀的開源框架,相反,Spring可以降低各種框架的使用難度,Spring提供了對各種優(yōu)秀框架(如Struts,Hibernate、Hessian、Quartz)等的直接支持。
◆降低Java EE API的使用難度
Spring對很多難用的Java EE API(如JDBC,JavaMail,遠程調用等)提供了一個薄薄的封裝層,通過Spring的簡易封裝,這些Java EE API的使用難度大為降低。
?
5.4.3 模塊結構
Spring核心容器(提供框架的基本功能,核心容器的組件是BeanFactory,是工廠模式的體現,使用IOC(控制反轉)模式將應用程序的配置和依賴性規(guī)范與實際的應用代碼分開)。
Spring上下文 是一個配置文件(applicationContext.xml),向框架提供上下文信息。包括的服務如JNDI,調度等。
Spring AOP 面向方面的編程,主要用于支持事務管理。
Spring Dao 提供異常層次結構,可管理異常處理和不同數據庫供應商拋出的錯誤信息。
Spring ORM 集成了多個ORM框架,提供ORM的對象關系工具。
Spring Web 集成了MVC的框架,如Struts等
Spring MVC 自身提供的MVC框架,高度的可配置性。
?
5.4.4 Ioc(控制反轉)
定義:由容器來控制業(yè)務和業(yè)務之間的依賴關系,而非傳統(tǒng)的通過代碼來直接操控,此處控制權的轉移就是所謂的反轉。
實現策略:依賴查找(類似與JDNI的實現)、依賴注入(DI)
其中依賴注入是一種更加合適的方法,讓容器去全權負責依賴查詢,受管組件只需要暴露JavaBean的setter方法或者帶參數的構造子或者接口,使容器可以在初始化時組裝對象的依賴關系。
好處是:查詢依賴操作和應用代碼分離;受控對象不會使用到容器特定的API,這樣我們的受控對象可以搬出容器單獨使用。
依賴注入有三種:又有接口注入(Interface Injection),設值注入(Setter Injection)和構造子注入(Constructor Injection)三種方式。
5.4.5 Ioc容器裝載機制
4種Bean封裝機制:
BeanWrapper機制
BeanFactory機制
ApplicationContext機制:由BeanFactory擴展而來。
WebContext機制
配置XML元數據:服務層對象、DAO數據訪問層對象、Action表示層對象、Hibernate SessionFactory對象、JMS Queue對象等。
舉例:
Object obj=Class.forName("domain.Test").newInstance();
BeanWrapperwrapper=newBeanWrapperImpl(obj);//BeanWrapper實現了Wrapper接口
wrapper.setPropertyValue("testN","sasa");
Testte=(Test)obj;
System.out.println(te.getTestN());
?
?
?
實例化容器
Resource r? = new FileSystemResource(“beans.xml”);
BeanFactory factory = new XmlBeanFactory(r);
或者
ClassPathResource r = new ClassPathResource(“beans.xml”);
BeanFactory factory = new XmlBeanFactory(r);
或者
ApplicationContext ctx = null;
ctx = new ClassPathXmlApplicationContext(new String[]{“beans1.xml”,”beans2.xml”});
BeanFactory factory = (BeanFactory)ctx;
注意:以上都是相對路徑。
?
BeanFactory提供的方法
Boolean containsBean(String);
Object getBean(String)
Object getBean(String,Class)
Class getType(String name)
Boolean isSingleton(String)
String[] getAliases(String) 通過bean名稱的所有別名
配置<bean>的屬性
id、class、factory-method(必須靜態(tài)的方法)、factory-bean(使用是class屬性必須為空)、scope(singleton、prototype、request、session、global session)、depends-on (指定依賴的bean))、lazy-init(true、false)、init-method(初始化回調)、destory-method(bean析構回調)、parent(繼承bean)
配置<bean>的子元素
<property>(主要是針對屬性注入)
簡單:name value
集合:
Properties 使用<props><prop key>value</prop></props>
List????? 使用<list><value>value</value></list>
Map???? 使用
<map>
<entry>
<key>
<value>value</value>
</key>
<value>value</value>
</entry>
</map>
Set????? 使用<set><value>value</value></set>
注意:map的key或value值,或set的value值不能是以下元素:bean、ref、idref、list、set、map、props、value、null。
配置<constructor-arg>元素
1、用type指定輸入參數的java類型,value指定輸入參數的值
2、用ref屬性指定其他的bean
3、使用<ref>子元素指向另一個bean
?
5.4.6 在web.xml中配置spring
?
上下文
<context-param>
???????? <param-name>contextConfigLocation</param-name>
???????? <param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>
監(jiān)聽
???? <listener>
???? <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
???? </listener>
字符集的設置
???? ?<filter>
???? ??????? <filter-name>encodingFilter</filter-name>
? ??? ??<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
???? ??????? <init-param>
???? ??????????? <param-name>encoding</param-name>
???? ??????????? <param-value>UTF-8</param-value>
???? ??????? </init-param>
???? ??????? <init-param>
???? ?? ?????????<param-name>forceEncoding</param-name>
???? ??????????? <param-value>true</param-value>
???? ??????? </init-param>
???? </filter>
???? <filter-mapping>
???? ??????? <filter-name>encodingFilter</filter-name>
???? ??????? <url-pattern>/*</url-pattern>
???? </filter-mapping>
?
5.4.7 Spring AOP
一、簡介
AOP也就是面向切面編程,作為面向對象編程的補充。面向切面編程(AOP)和面向對象編程(OOP)互為補充,面向對象編程將程序分解成各個層次的對象,而面向切面編程將程序運行過程分解成各個切面,可以這樣理解,面向對象編程從靜態(tài)角度考慮程序結構,面向切面編程是從動態(tài)角度考慮運行過程。AOP專門用來處理具有橫切性質的系統(tǒng)服務,如事務管理、安全檢查、緩存、對象池管理等。
二、概念
切面(Aspect):業(yè)務流程運行的某個特定步驟,也就是應用運行過程中的關注點,關注點可以橫切多個對象,所以常常也稱為橫切關注點。
連接點(Joinpoint):程序運行過程中明確的點,如方法的調用,或者異常的拋出。Spring AOP中,連接點總是方法的調用,指的就是Method。
增強處理(Advice):AOP框架在特定的切入點執(zhí)行的增強處理。處理有”around”、”before”、”after”等類型。
切入點(Pointcut):可以插入增強處理的連接點。簡而言之,當某個連接點滿足指定要求時,該連接點將被添加增強處理,該連接點也就變成了切入點。
一組Joinpoint,就是說一個Advice可能在多個地方織入。
?
引入:將方法或者字段添加到被處理的類中。Spring允許引入新的接口到任何被處理的對象。
目標對象(Target):被AOP框架進行增強處理的對象,也被稱為增強的對象。如果AOP框架是通過運行時代理來實現的,那么這個對象是一個被代理的對象。
AOP代理:AOP框架創(chuàng)建的對象,簡單地說代理就是對目標對象的加強。Spring中的AOP代理可以是JDK動態(tài)代理,也可以是DBLIB代理。前者為實現接口的目標對象的代理,后者為不實現接口的目標對象的代理。
織入(Weaving):將增強處理添加到目標對象中,并創(chuàng)建一個被增強的對象(AOP代理)的過程就是織入。織入有兩種方式:編譯時增強(AspectJ)和運行時增強(DGLIB)。
?
三、AOP 種類
1、靜態(tài)織入:指在編譯時期就織入Aspect代碼,AspectJ好像是這樣做的。
2、動態(tài)織入:在運行時期織入,Spring AOP屬于動態(tài)織入,動態(tài)織入又分靜動兩種,靜則指織入過程只在第一次調用時執(zhí)行;動則指根據代碼動態(tài)運行的中間狀態(tài)來決定如何操作,每次調用Target的時候都執(zhí)行(性能較差)。
?
四、Spring AOP 代理原理
Spring AOP 是使用代理來完成的,Spring 會使用下面兩種方式的其中一種來創(chuàng)建代理:
1、JDK動態(tài)代理,特點只能代理接口,性能相對較差,需要設定一組代理接口。
2、CGLIB 代理,可代理接口和類(final method除外),性能較高(生成字節(jié)碼)。
五、常用增強處理
@Before("execution(* kuozhan.before.*.*(..))")
@AfterReturning(pointcut="execttion(* kuozhan.after.*.*(..))",returning="rvt")
@AfterThrowing(pointcut="execution(* lee.*.*(..))", throwing="ex")
@After("execution(* lee.*.*(..))")
@Around("execution(* lee.*.*(..))")
?
?
?
5.5 如何集成三個框架
6、設計模式
6.1設計模式的目的
設計模式(Design pattern)是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性、可維護性。 毫無疑問,設計模式于己于他人于系統(tǒng)都是多贏的,設計模式使代碼編制真正工程化,設計模式是軟件工程的基石,如同大廈的一塊塊磚石一樣。
6.2設計模式的原則
6.2.1開閉原則
開閉原則(對擴展開放,對修改關閉)
如簡單工廠模式,只要再創(chuàng)建一個子類就可以了,然后在工廠的方法中返回一個新的子類對象就可以了。
6.2.2里氏替換原則
里氏替換原則(任何基類可以出現的地方,子類一定可以出現)
如果調用的是父類的話,那么換成子類也完全可以運行。Java編譯程序會檢查程序是否符合里氏代換原則。還記得java繼承的一個原則嗎?子類override方法的訪問權限不能小于父類對應方法的訪問權限。可以說:里氏代換原則是繼承復用的一個基礎。
6.2.3合成復用原則
合成復用原則(少用繼承,多用合成/聚合)
在面向對象的設計里,有兩種基本的辦法可以在不同的環(huán)境中復用已有的設計和實現,即通過合成/聚合或通過繼承。
?
合成/聚合復用:
優(yōu)點:支持包裝、黑箱復用看不見內部的細節(jié)。依賴較少。這種復用可以在運行時間內動態(tài)進行,新對象可以動態(tài)地引用與成分對象類型相同的對象。
缺點:是通過使用這種復用建造的系統(tǒng)會有較多的對象需要管理
?
繼承復用:
優(yōu)點:新的實現較為容易,因為超類的大部分功能都可以通過繼承關系自動進入子類,修改或擴展繼承而來的實現較為容易。
缺點:繼承復用破壞包裝,因為繼承將超類的實現細節(jié)暴露給子類。因為超類的內部細節(jié)常常是對子類透明的,因此這種復用是透明的復用,又稱“白箱”復用。如果超類的實現發(fā)生改變,那么子類的實現也不得不發(fā)生改變。從超類忌辰而來的實現是靜態(tài)的,不可能在運行時間內發(fā)生改變,因此沒有足夠的靈活性。
一般來說,對違反里氏代換原則的設計進行重構時,可以采取兩種辦法:一是加入一個抽象超類;二是將繼承關系改寫為合成/聚合關系。
“IS-A”是嚴格的分類學意義上的定義,意思是一個類是另一個類的“一種”。而“HAS-A”則不同,它表示某一個角色具有某一項責任。
6.2.4 依賴倒置原則
依賴倒置原則(抽象不應該依賴于細節(jié),細節(jié)應當依賴于抽象)
要針對接口編程,而不是針對實現編程。
傳遞參數,或者在組合聚合關系中,盡量引用層次高的類。
主要是在構造對象時可以動態(tài)的創(chuàng)建各種具體對象,當然如果一些具體類比較穩(wěn)定,就不必在弄一個抽象類做它的父類,這樣有畫蛇添足的感覺。
6.2.5 接口隔離原則
接口隔離原則(使用多個專門的接口比使用單一的總接口要好)
一個類對另外一個類的依賴性應當是建立在最小的接口上的。
一個接口代表一個角色,不應當將不同的角色都交給一個接口。沒有關系的接口合并在一起,形成一個臃腫的大接口,這是對角色和接口的污染。
“不應該強迫客戶依賴于它們不用的方法。接口屬于客戶,不屬于它所在的類層次結構。”這個說得很明白了,再通俗點說,不要強迫客戶使用它們不用的方法,如果強迫用戶使用它們不使用的方法,那么這些客戶就會面臨由于這些不使用的方法的改變所帶來的改變。
?
6.2.6迪米特原則
迪米特原則(最少知識原則。不要和陌生人說話)
迪米特法則的各種表述
① 只與你直接的朋友們通信;
② 不要跟“陌生人”說話;
③ 每一個軟件單位對其他的單位都只有最少的知識,而且局限于那些與本單位密切相關的軟件單位。
狹義的迪米特法則
☆ 如果兩個類不必彼此直接通信,那么這兩個類就不應當發(fā)生直接的相互作用。如果其中的一個類需要調用另外一個類的某一個方法,可以通過第三者轉發(fā)這個調用。
?
?
在系統(tǒng)里造出大量的小方法,這些方法僅僅是傳遞間接的調用,與系統(tǒng)的商務邏輯無關。
遵循類之間的迪米特法則會是一個系統(tǒng)的局部設計簡化,因為每一個局部都不會和遠距離的對象有直接的關聯。但是,這也會造成系統(tǒng)的不同模塊之間的通信效率降低,也會使系統(tǒng)的不同模塊之間不容易協(xié)調。
門面模式和調停者模式實際上就是迪米特法則的應用。
廣義的迪米特法則在類的設計上的體現:
優(yōu)先考慮將一個類設置成不變類。
盡量降低一個類的訪問權限。
謹慎使用Serializable。
盡量降低成員的訪問權限。
?
?
注意:在進行設計的時候,我們盡量從抽象類繼承,而不是從具體類繼承。如果從繼承等級樹來看,所有葉子節(jié)點應當是具體類,而所有的樹枝節(jié)點應當是抽象類或者接口。當然這個只是一個一般性的指導原則,使用的時候還要具體情況具體分析。
6.3模式的四個要素
6.3.1 模式名稱
模式名稱:一個助記名,它用一兩個詞來描述模式的問題、解決方案和效果。
6.3.2 問題
問題:描述了應該在何時使用模式。
6.3.3 解決方案
解決方案:描述了設計的組成成分,它們之間的相互關系及各自的職責和協(xié)作方式。
6.3.4 效果
效果:描述了模式應用的效果及使用模式應權衡的問題。
6.4創(chuàng)建模式
6.4.1抽象工廠模式
提供一個創(chuàng)建一系列相關或相互依賴對象的接口,而無須指定它們的具體類。客戶類和工廠類分開。消費者任何時候需要某種產品,只需向工廠請求即可。消費者無須修改就可以接納新產品。缺點是當產品修改時,工廠類也要做相應的修改。
?
6.4.2生成器模式
生成器模式也稱為建造者模式。將一個復雜對象的構建與他的表示相分離,使得同樣的構建過程可以創(chuàng)建不同的表示。將產品的內部表象和產品的生成過程分割開來,從而使一個建造過程生成具有不同的內部表象的產品對象。建造模式使得產品內部表象可以獨立的變化,客戶不必知道產品內部組成的細節(jié)。建造模式可以強制實行一種分步驟進行的建造過程。
?
?
6.4.3工廠方法模式
核心工廠類不再負責所有產品的創(chuàng)建,而是將具體創(chuàng)建的工作交給子類去做,成為一個抽象工廠角色,僅負責給出具體工廠類必須實現的接口,而不接觸哪一個產品類應當被實例化這種細節(jié)。
?
?
簡單工廠模式
?
6.4.4原型模式
通過給出一個原型對象來指明所要創(chuàng)建的對象的類型,然后用復制這個原型對象的方法創(chuàng)建出更多同類型的對象。原始模型模式允許動態(tài)的增加或減少產品類,產品類不需要非得有任何事先確定的等級結構,原始模型模式適用于任何的等級結構。缺點是每一個類都必須配備一個克隆方法。
?
在Java中Prototype模式變成clone()方法的使用,由于Java的純潔的面向對象特性,使得在Java中使用設計模式變得很自然,兩者已經幾乎是渾然一體了。這反映在很多模式上,如Iterator遍歷模式。
6.4.5單例模式
保證一個類只有一個實例,并提供一個訪問它的全局訪問點
6.5行為模式
6.5.1 迭代器模式
提供一個方法順序訪問一個聚合對象的各個元素,而又不需要暴露該對象的內部表示。
?
6.5.2 觀察者模式
定義對象間一對多的依賴關系,當一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知自動更新(之前寫的天氣預報)。
?
6.5.3 模板方法模式
定義一個操作中的算法的骨架,而將一些步驟延遲到子類中,TemplateMethod使得子類可以不改變一個算法的結構即可以重定義該算法得某些特定步驟。
6.5.4 命令模式
將一個請求封裝為一個對象,從而使你可以用不同的請求對客戶進行參數化,對請求排隊和記錄請求日志,以及支持可撤銷的操作。Command模式是非常簡單而又優(yōu)雅的一種設計模式,它的根本目的在于將“行為請求者”與“行為實現者”解耦。
?
?
?
6.5.5 狀態(tài)模式
允許對象在其內部狀態(tài)改變時改變他的行為。對象看起來似乎改變了他的類。主要解決的是當控制一個對象狀態(tài)的條件表達式過于復雜時的情況。把狀態(tài)的判斷邏輯轉移到表示不同狀態(tài)的一系列類中,可以把復雜的判斷邏輯簡化。
意圖:允許一個對象在其內部狀態(tài)改變時改變它的行為
適用場景:
1.一個對象的行為取決于它的狀態(tài),并且它必須在運行時刻根據狀態(tài)改變它的行為。
2.一個操作中含有龐大的多分支結構,并且這些分支決定于對象的狀態(tài)。
策略模式和狀態(tài)模式是雙胞胎,它們有相同的類圖,但是它們的意圖不同。策略模式是圍繞可以互換的算法來成功創(chuàng)建業(yè)務的,然而狀態(tài)模式是通過改變對象內部的狀態(tài)來幫助對象控制自己的行為。
?
6.5.6 策略模式
定義一系列的算法,把他們一個個封裝起來,并使他們可以互相替換,本模式使得算法可以獨立于使用它們的客戶。
?
優(yōu)點:
1、 提供了一種替代繼承的方法,而且既保持了繼承的優(yōu)點(代碼重用)還比繼承更靈活(算法獨立,可以任意擴展)。
2、 避免程序中使用多重條件轉移語句,使系統(tǒng)更靈活,并易于擴展。
3、 遵守大部分GRASP原則和常用設計原則,高內聚、低偶合。
缺點:
1、 因為每個具體策略類都會產生一個新類,所以會增加系統(tǒng)需要維護的類的數量。
見例子:
1. 抽象策略
package com.eekq.strategy;
?
public interface IStrategy {
?
??? /**策略方法*/
? ??public abstract double add();
}
2. 具體策略,這里我以兩個具體策略為例
package com.eekq.strategy;
?
public class ConcreteStrategy1 implements IStrategy {
?
??? /**示意性算法*/
??? public double add() {
??????? // TODO 自動生成方法存根
??????? System.out.println(this.getClass().getName() + "的加法運算");
??????? return 0;
??? }
?
}
package com.eekq.strategy;
?
public class ConcreteStrategy2 implements IStrategy {
?
??? public double add() {
??????? // TODO 自動生成方法存根
??????? System.out.println(this.getClass().getName() + "的加法運算");
??????? return 0;
??? }
?
}
3.環(huán)境角色
package com.eekq.strategy;
?
public class Context {
??? /**環(huán)境角色類*/
??? private IStrategy strategy;
?
??? public Context(IStrategy strategy) {
??????? this.strategy = strategy;
??? }
?
??? /**策略方法*/
??? public double add() {
??????? this.strategy.add();
??????? return 0;
??? }
}
4.客戶端調用
package com.eekq.strategy;
?
public class Main {
?
??? /**
???? *@paramargs
???? */
??? public static void main(String[] args) {
??????? // TODO 自動生成方法存根
??????? Context context = new Context(new ConcreteStrategy1());
??????? context.add();//執(zhí)行算法1
??????? context = new Context(new ConcreteStrategy2());
??????? context.add();//執(zhí)行算法2
??? }
?
}
5.執(zhí)行結果:
com.eekq.strategy.ConcreteStrategy1的加法運算
com.eekq.strategy.ConcreteStrategy2的加法運算
6.總結
優(yōu)點:動態(tài)改變算法或行為
缺點:客戶端必須知道所有的策略類,并自行決定使用哪一個策略類,必須對每一個算法了解
6.5.7 職責鏈模式
使多個對象都有機會處理請求,從而避免請求的送發(fā)者和接收者之間的耦合關系 。一個鏈可以是一條線,一個樹,也可以是一個環(huán)。如下圖所示,責任鏈是一個樹結構的一部分。在責任鏈模式里,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。發(fā)出這個請求的客戶端并不知道鏈上的哪一個對象最終處理這個請求,這使得系統(tǒng)可以在不影響客戶端的情況下動態(tài)地重新組織鏈和分配責任。
?
//?"Handler"
abstract?class?Handler
{
??//?Fields
??protected?Handler?successor;
?
??//?Methods
??public?void?SetSuccessor(?Handler?successor?)
??{
????this.successor?=?successor;
??}
??abstract?public?void?HandleRequest(?int?request?);
}
//?"ConcreteHandler1"
class?ConcreteHandler1?:?Handler
{
??//?Methods
??override?public?void?HandleRequest(?int?request?)
??{
????if(?request?>=?0?&&?request?<?10?)
??????Console.WriteLine("{0}?handled?request?{1}",
????????this,?request?);
????else
??????if(?successor?!=?null?)
??????successor.HandleRequest(?request?);
??}
}
6.5.8 中介者模式
中介者又叫調停者,用一個中介對象封裝一些列的對象交互。
?
6.5.9 訪問者模式
表示一個作用于某對象結構中的各元素的操作,它使你可以在不改變各元素類的前提下定義作用于這個元素的新操作。訪問者模式用于對不同節(jié)點進行操作的情況(如List的中的多個元素并不相同),如果將操作放在節(jié)點中,會增加節(jié)點的復雜性,并不易維護,如果將操作放在調用函數中,則會出現多個判斷語句,對不同的節(jié)點做不同的操作,增加了節(jié)點和調用函數之間的耦合。為了解決這樣的問題,在調用函數(對節(jié)點進行操作的函數)和節(jié)點之間增加了vistor的類,在vistor中實現對各個節(jié)點的操作。
?
6.5.10 解釋器模式
給定一個語言,定義他的文法的一個表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。
?
6.5.11 備忘錄模式
在不破壞對象的前提下,捕獲一個對象的內部狀態(tài),并在該對象之外保存這個狀態(tài)。
?
6.6結構模式
6.6.1組合模式
將對象組合成樹形結構以表示部分整體的關系,Composite使得用戶對單個對象和組合對象的使用具有一致性。
?
6.6.2 外觀模式
為子系統(tǒng)中的一組接口提供一致的界面,fa?ade提供了一高層接口,這個接口使得子系統(tǒng)更容易使用。
?
6.6.3 代理模式
為其他對象提供一種代理以控制對這個對象的訪問
?
6.6.4 適配器模式
將一類的接口轉換成客戶希望的另外一個接口,Adapter模式使得原本由于接口不兼容而不能一起工作那些類可以一起工作。
?
6.6.5 裝飾模式
動態(tài)地給一個對象增加一些額外的職責,就增加的功能來說,Decorator模式相比生成子類更加靈活。
?
6.6.6 橋模式
將抽象部分與它的實現部分相分離,使他們可以獨立的變化。
?
6.6.7 享元模式
用來盡可能減少內存使用量以及分享資訊給盡可能多的相似物件;它適合用于當大量物件只是重復因而導致無法令人接受的使用大量內存。通常物件中的部分狀態(tài)是可以分享。常見做法是把它們放在外部數據結構,當需要使用時再將它們傳遞給享元。
?
?
7、J2EE核心組件
7.1 JDBC(JAVA數據庫連接)
JDBC(Java Database Connectivity): JDBC API為訪問不同的數據庫提供了一種統(tǒng)一的途徑,象ODBC一樣,JDBC對開發(fā)者屏蔽了一些細節(jié)問題,另外,JDCB對數據庫的訪問也具有平臺無關性。
7.2 JNDI(JAVA命名和目錄服務接口)
1、JNDI(Java Name and Directory Interface): JNDI API被用于執(zhí)行名字和目錄服務。它提供了一致的模型來存取和操作企業(yè)級的資源如DNS和LDAP,本地文件系統(tǒng),或應用服務器中的對象。
2、JNDI(Java Naming and Directory Interface)是一個應用程序設計的API,為開發(fā)人員提供了查找和訪問各種命名和目錄服務的通用、統(tǒng)一的接口,類似JDBC都是構建在抽象層上。
3、JNDI可訪問的現有的目錄及服務有:
DNS、XNam 、Novell目錄服務、LDAP(Lightweight Directory Access Protocol 輕型目錄訪問協(xié)議)、 CORBA對象服務、文件系統(tǒng)、Windows XP/2000/NT/Me/9x的注冊表、RMI、DSML v1&v2、NIS。
4、優(yōu)點:
包含了大量的命名和目錄服務,使用通用接口來訪問不同種類的服務;
可以同時連接到多個命名或目錄服務上;
建立起邏輯關聯,允許把名稱同Java對象或資源關聯起來,而不必知道對象或資源的物理ID。
5、JNDI與JDBC
JNDI提供了一種統(tǒng)一的方式,可以用在網絡上查找和訪問服務。通過指定一個資源名稱,該名稱對應于數據庫或命名服務中的一個記錄,同時返回數據庫連接建立所必須的信息。
JNDI主要有兩部分組成:應用程序編程接口和服務供應商接口。應用程序編程接口提供了Java應用程序訪問各種命名和目錄服務的功能,服務供應商接口提供了任意一種服務的供應商使用的功能。
代碼示例:
try{
Context cntxt = new InitialContext();
DataSource ds = (DataSource) cntxt.lookup("jdbc/dpt");
}
catch(NamingException ne){
...
}
6、JNDI與JMS
消息通信是軟件組件或應用程序用來通信的一種方法。JMS就是一種允許應用程序創(chuàng)建、發(fā)送、接收、和讀取消息的JAVA技術。
代碼示例:
try{
Properties env = new Properties();
InitialContext inictxt = new InitialContext(env);
TopicConnectionFactory connFactory = (TopicConnectionFactory) inictxt.lookup("TTopicConnectionFactory");
...
}
catch(NamingException ne){
...
}
訪問特定目錄:舉個例子,人是個對象,他有好幾個屬性,諸如這個人的姓名、電話號碼、電子郵件地址、郵政編碼等屬性。
通過getAttributes()方法
Attribute attr = directory.getAttributes(personName).get("email");
String email = (String)attr.get();
通過使用JNDI讓客戶使用對象的名稱或屬性來查找對象:
foxes = directory.search("o=Wiz,c=US", "sn=Fox", controls);
通過使用JNDI來查找諸如打印機、數據庫這樣的對象,查找打印機的例子: Printer printer = (Printer)namespace.lookup(printerName); printer.print(document);
瀏覽命名空間:
NamingEnumeration list = namespace.list("o=Widget, c=US"); while (list.hasMore()) {
NameClassPair entry = (NameClassPair)list.next(); display(entry.getName(), entry.getClassName());
}
?
?
?
7.3 EJB(JAVA企業(yè)bean)
EJB(Enterprise JavaBean): J2EE技術之所以贏得某體廣泛重視的原因之一就是EJB。它們提供了一個框架來開發(fā)和實施分布式商務邏輯,由此很顯著地簡化了具有可伸縮性和高度復雜的企業(yè)級應用的開發(fā)。EJB規(guī)范定義了EJB組件在何時如何與它們的容器進行交互作用。容器負責提供公用的服務,例如目錄服務、事務管理、安全性、資源緩沖池以及容錯性。但這里值得注意的是,EJB并不是實現J2EE的唯一途徑。正是由于J2EE的開放性,使得有的廠商能夠以一種和EJB平行的方式來達到同樣的目的。
分類:分別是會話Bean(Session Bean),實體Bean(Entity Bean)和消息驅動Bean(MessageDriven Bean)。
1.Session Bean用于實現業(yè)務邏輯,它可以是有狀態(tài)的,也可以是無狀態(tài)的。每當客戶端請求時,容器就會選擇一個Session Bean來為客戶端服務。Session Bean可以直接訪問數據庫,但更多時候,它會通過Entity Bean實現數據訪問。
2.Entity Bean是域模型對象,用于實現O/R映射,負責將數據庫中的表記錄映射為內存中的Entity對象,事實上,創(chuàng)建一個Entity Bean對象相當于新建一條記錄,刪除一個Entity Bean會同時從數據庫中刪除對應記錄,修改一個Entity Bean時,容器會自動將Entity Bean的狀態(tài)和數據庫同步。
3.MessageDriven Bean是EJB2.0中引入的新的企業(yè)Bean,它基于JMS消息,只能接收客戶端發(fā)送的JMS消息然后處理。MDB實際上是一個異步的無狀態(tài)Session Bean,客戶端調用MDB后無需等待,立刻返回,MDB將異步處理客戶請求。這適合于需要異步處理請求的場合,比如訂單處理,這樣就能避免客戶端長時間的等待一個方法調用直到返回結果。
7.4 RMI(遠程方法調用)
RMI(Remote Method Invoke): 正如其名字所表示的那樣,RMI協(xié)議調用遠程對象上方法。它使用了序列化方式在客戶端和服務器端傳遞數據。RMI是一種被EJB使用的更底層的協(xié)議。
舉例:
//接口RmiSample
import java.rmi.Remote;
import java.rmi.RemoteException;
?
public interface RmiSample extends Remote {
??? public int sum(int a, int b) throws RemoteException;
}
//實現類RmiSampleImpl
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
?
public class RmiSampleImpl extends UnicastRemoteObject implements RmiSample {
?
??? protected RmiSampleImpl() throws RemoteException {
?????? super();
?????? // TODO Auto-generated constructor stub
??? }
??? @Override
??? public int sum(int a, int b) throws RemoteException {
?????? // TODO Auto-generated method stub
?????? return a+b;
??? }
}
//服務器RmiSampleServer
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
?
public class RmiSampleServer {
?
??? /**
??? ?* @param args
??? ?*/
??? public static void main(String[] args) {
?????? // TODO Auto-generated method stub
?????? try {LocateRegistry.createRegistry(8083) ;
?????????? RmiSampleImpl? Server = new RmiSampleImpl();
?????????? // 將該對象實例與名稱“SAMPLE-SERVER”捆綁
?????????? Naming.rebind("rmi://localhost:8083/SAMPLE-SERVER" , Server);
??? ??? } catch (java.net.MalformedURLException me) {
?????????? System.out.println("Malformed URL: " + me.toString());
?????? } catch (RemoteException re) {
?????????? System.out.println("Remote exception: " + re.toString());
?????? }
??? }
}
//客戶端
import java.rmi.Naming;
import java.rmi.RemoteException;
?
public class RmiSampleClient {
?
??? /**
??? ?* @param args
??? ?*/
??? public static void main(String[] args) {
?????? // TODO Auto-generated method stub
?????? try {
?????????? String url = "rmi://localhost:8083/SAMPLE-SERVER";
?????????? RmiSample RmiObject = (RmiSample) Naming.lookup(url);
?????????? System.out.println(" 1 + 2 = " + RmiObject.sum(1, 2));
?????? } catch (RemoteException exc) {
?????????? System.out.println("Error in lookup: " + exc.toString());
?????? } catch (java.net.MalformedURLException exc) {
?????????? System.out.println("Malformed URL: " + exc.toString());
?????? } catch (java.rmi.NotBoundException exc) {
?????????? System.out.println("NotBound: " + exc.toString());
?????? }
??? }
}
?
7.5 Java IDL/CORBA
Java IDL/CORBA: 在Java IDL的支持下,開發(fā)人員可以將Java和CORBA集成在一起。他們可以創(chuàng)建Java對象并使之可在CORBA ORB中展開, 或者他們還可以創(chuàng)建Java類并作為和其它ORB一起展開的CORBA對象的客戶。后一種方法提供了另外一種途徑,通過它Java可以被用于將你的新的應用和舊的系統(tǒng)相集成。
CORBA的核心是開放軟件總線——ORB,它提供了網絡環(huán)境無關性、操作系統(tǒng)無關性和開發(fā)語言無關性的公共平臺。在面向對象的應用環(huán)境中,CORBA對象(本文所說的“對象”是面向對象系統(tǒng)中的術語,是指一個實體)的請求者不必知道它所請求的對象是在哪里,是如何實現的,而是由ORB來負責跨平臺的運作管理,無須應用系統(tǒng)的開發(fā)者干預。CORBA所具有的跨平臺、分布式、面向對象的這些優(yōu)點使它具有廣闊的應用前景,日益受到軟件行業(yè)的重視。
CORBA是一個中間件規(guī)范并不是一個實體軟件。軟件開發(fā)者通過使用第三方的ORB工具或IDL語言來定義CORBA對象,實現ORB功能。
7.6 JSP
JSP(Java Server Pages): JSP頁面由HTML代碼和嵌入其中的Java代碼所組成。服務器在頁面被客戶端所請求以后對這些Java代碼進行處理,然后將生成的HTML頁面返回給客戶端的瀏覽器。
7.7 Java Servlet
Servlet是一種小型的Java程序,它擴展了Web服務器的功能。作為一種服務器端的應用,當被請求時開始執(zhí)行,這和CGI Perl腳本很相似。Servlet提供的功能大多與JSP類似,不過實現的方式不同。JSP通常是大多數HTML代碼中嵌入少量的Java代碼,而servlets全部由Java寫成并且生成HTML。
7.8 XML(Extensible Markup Language)
XML是一種可以用來定義其它標記語言的語言。它被用來在不同的商務過程中共享數據。XML的發(fā)展和Java是相互獨立的,但是,它和Java具有的相同目標正是平臺獨立性。通過將Java和XML的組合,您可以得到一個完美的具有平臺獨立性的解決方案。
7.9 JMS(Java Message Service)
7.9.1 簡介
JMS是用于和面向消息的中間件相互通信的應用程序接口(API)。它既支持點對點的域,有支持發(fā)布/訂閱(publish/subscribe)類型的域,并且提供對下列類型的支持:經認可的消息傳遞,事務型消息的傳遞,一致性消息和具有持久性的訂閱者支持。JMS還提供了另一種方式來對您的應用與舊的后臺系統(tǒng)相集成。
JMS即Java消息服務(Java Message Service)應用程序接口是一個Java平臺中關于面向消息中間件(MOM)的API,用于在兩個應用程序之間,或分布式系統(tǒng)中發(fā)送消息,進行異步通信。
JMS 使您能夠通過消息收發(fā)服務(有時稱為消息中介程序或路由器)從一個 JMS 客戶機向另一個 JMS客戶機發(fā)送消息。消息是 JMS 中的一種類型對象,由兩部分組成:報頭和消息主體。報頭由路由信息以及有關該消息的元數據組成。消息主體則攜帶著應用程序的數據或有效負載。根據有效負載的類型來劃分,可以將消息分為幾種類型,它們分別攜帶:簡單文本 (TextMessage)、可序列化的對象 (ObjectMessage)、屬性集合 (MapMessage)、字節(jié)流 (BytesMessage)、原始值流 (StreamMessage),還有無有效負載的消息 (Message)。
7.9.2 JMS的組成
JMS提供者
連接面向消息中間件的,JMS接口的一個實現。提供者可以是Java平臺的JMS實現,也可以是非Java平臺的面向消息中間件的適配器。
JMS客戶
生產或消費基于消息的Java的應用程序或對象。
JMS生產者
創(chuàng)建并發(fā)送消息的JMS客戶。
JMS消費者
接收消息的JMS客戶。
JMS消息
包括可以在JMS客戶之間傳遞的數據的對象
JMS隊列
一個容納那些被發(fā)送的等待閱讀的消息的區(qū)域。隊列暗示,這些消息將按照順序發(fā)送。一旦一個消息被閱讀,該消息將被從隊列中移走。
JMS主題
一種支持發(fā)送消息給多個訂閱者的機制。
7.9.3 JMS應用程序接口
ConnectionFactory 接口(連接工廠)
用戶用來創(chuàng)建到JMS提供者的連接的被管對象。JMS客戶通過可移植的接口訪問連接,這樣當下層的實現改變時,代碼不需要進行修改。 管理員在JNDI名字空間中配置連接工廠,這樣,JMS客戶才能夠查找到它們。根據消息類型的不同,用戶將使用隊列連接工廠,或者主題連接工廠。
Connection 接口(連接)
連接代表了應用程序和消息服務器之間的通信鏈路。在獲得了連接工廠后,就可以創(chuàng)建一個與JMS提供者的連接。根據不同的連接類型,連接允許用戶創(chuàng)建會話,以發(fā)送和接收隊列和主題到目標。
Destination 接口(目標)
目標是一個包裝了消息目標標識符的被管對象,消息目標是指消息發(fā)布和接收的地點,或者是隊列,或者是主題。JMS管理員創(chuàng)建這些對象,然后用戶通過JNDI發(fā)現它們。和連接工廠一樣,管理員可以創(chuàng)建兩種類型的目標,點對點模型的隊列,以及發(fā)布者/訂閱者模型的主題。
MessageConsumer 接口(消息消費者)
由會話創(chuàng)建的對象,用于接收發(fā)送到目標的消息。消費者可以同步地(阻塞模式),或異步(非阻塞)接收隊列和主題類型的消息。
MessageProducer 接口(消息生產者)
由會話創(chuàng)建的對象,用于發(fā)送消息到目標。用戶可以創(chuàng)建某個目標的發(fā)送者,也可以創(chuàng)建一個通用的發(fā)送者,在發(fā)送消息時指定目標。
Message 接口(消息)
是在消費者和生產者之間傳送的對象,也就是說從一個應用程序傳送到另一個應用程序。一個消息有三個主要部分:
消息頭(必須):包含用于識別和為消息尋找路由的操作設置。
一組消息屬性(可選):包含額外的屬性,支持其他提供者和用戶的兼容。可以創(chuàng)建定制的字段和過濾器(消息選擇器)。
一個消息體(可選):允許用戶創(chuàng)建五種類型的消息(文本消息,映射消息,字節(jié)消息,流消息和對象消息)。
消息接口非常靈活,并提供了許多方式來定制消息的內容。
Session 接口(會話)
表示一個單線程的上下文,用于發(fā)送和接收消息。由于會話是單線程的,所以消息是連續(xù)的,就是說消息是按照發(fā)送的順序一個一個接收的。會話的好處是它支持事務。如果用戶選擇了事務支持,會話上下文將保存一組消息,直到事務被提交才發(fā)送這些消息。在提交事務之前,用戶可以使用回滾操作取消這些消息。一個會話允許用戶創(chuàng)建消息生產者來發(fā)送消息,創(chuàng)建消息消費者來接收消息。
7.9.4 JMS特性
1. 消息通信模型
JMS 支持兩種消息通信模型:點到點(point-to-point)(PTP)模型和發(fā)布/訂閱(Pub/Sub)模型。除了下列不同之外,這兩種消息通信模型非常地相似:
PTP 模型規(guī)定了一個消息只能有一個接收者;Pub/Sub 模型允許一個消息可以有多個接收者。
2. 消息組成
消息傳遞系統(tǒng)的中心就是消息。
一條 Message 分為三個組成部分:
頭(header)是個標準字段集,客戶機和供應商都用它來標識和路由消息。
屬性(property)支持把可選頭字段添加到消息。如果您的應用程序需要不使用標準頭字段對消息編目和分類,您就可以添加一個屬性到消息以實現這個編目和分類。提供 set<Type>Property(...) 和 get<Type>Property(...) 方法以設置和獲取各種 Java 類型的屬性,包括 Object。JMS 定義了一個供應商選擇提供的標準屬性集。
消息的主體(body)包含要發(fā)送給接收應用程序的內容。每個消息接口特定于它所支持的內容類型。
JMS 為不同類型的內容提供了它們各自的消息類型,但是所有消息都派生自 Message 接口。
StreamMessage:包含 Java 基本數值流,用標準流操作來順序的填充和讀取。
MapMessage:包含一組名/值對;名稱為 string 類型,而值為 Java 的基本類型。
TextMessage:包含一個 String。
ObjectMessage:包含一個 Serializable Java 對象;能使用 JDK 的集合類。
BytesMessage:包含未解釋字節(jié)流: 編碼主體以匹配現存的消息格式。
XMLMessage: 包含XML內容。擴展TextMessage,XMLMessage 類型的使用,使得消息過濾非常便利。
3. 消息確認模式
非事務性會話中,應用程序創(chuàng)建的會話有5 種確認模式,而在事務性會話中,確認模式被忽略。
五種確認模式說明:
AUTO_ACKNOWLEDGE:自動確認模式。一旦接收方應用程序的方法調用從處理消息處返回,會話對象就會確認消息的接收。
CLIENT_ACKNOWLEDGE:客戶端確認模式。會話對象依賴于應用程序對被接收的消息調用一個acknowledge()方法。一旦這個方法被調用,會話會確認最后一次確認之后所有接收到的消息。這種模式允許應用程序以一個調用來接收,處理并確認一批消息。注意:在管理控制臺中,如果連接工廠的Acknowledge Policy(確認方針)屬性被設置為"Previous"(提前),但是你希望為一個給定的會話確認所有接收到的消息,那么就用最后一條消息來調用acknowledge()方法。
DUPS_OK_ACKNOWLEDGE:允許副本的確認模式。一旦接收方應用程序的方法調用從處理消息處返回,會話對象就會確認消息的接收;而且允許重復確認。在需要考慮資源使用時,這種模式非常有效。注意:如果你的應用程序無法處理重復的消息的話,你應該避免使用這種模式。如果發(fā)送消息的初始化嘗試失敗,那么重復的消息可以被重新發(fā)送。
NO_ACKNOWLEDGE:不確認模式。不確認收到的消息是需要的。消息發(fā)送給一個NO_ACKNOWLEDGE 會話后,它們會被WebLogic 服務器立即刪除。在這種模式下,將無法重新獲得已接收的消息,而且可能導致下面的結果:1. 消息可能丟失;和(或者)另一種情況:2. 如果發(fā)送消息的初始化嘗試失敗,會出現重復消息被發(fā)送的情況。
MULTICAST_NO_ACKNOWLEDGE:IP組播下的不確認模式,同樣無需確認。發(fā)送給一個MULTICAST_NO_ACKNOWLEDGE會話的消息, 會共享之前所述的NO_ACKNOWLEDGE 確認模式一樣的特征。這種模式支持希望通過IP 組播方式進行消息通信的應用程序,而且無需依賴會話確認提供的服務質量。注意:如果你的應用程序無法處理消息的丟失或者重復,那么你應該避免使用這種模式。如果發(fā)送消息的初始化嘗試失敗的話,重復的消息可能會被再次發(fā)送。
注:在上表的5 種確認模式中,AUTO_ACKNOWLEDGE ,DUPS_OK_ACKNOWLEDGE 和CLIENT_ACKNOWLEDGE 是JMS 規(guī)范定義的,NO_ACKNOWLEDGE 和MULTICAST_NO_ACKNOWLEDGE是WebLogic JMS 提供的。
//獲取初始化容器
??? private static InitialContext getInitialContext() throws NamingException {
?????? Hashtable env = new Hashtable();
?????? env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
?????? env.put(Context.PROVIDER_URL, PROVIDER_URL);
?????? return new InitialContext(env);
??? }
?
具體列子,在weblogic中配置JMS服務器
1、新建JMS Servers
2、新建JMS Model
3、新建工廠
4、新建隊列(點對點)(或新建發(fā)布/訂閱)
代碼:
點對點:寫一個服務類(發(fā)送類),以及一個客戶端類(接受類)
//代碼略
訂閱/發(fā)布模式
?????????? //發(fā)布者部分代碼
ctx = new InitialContext();
?
?????????? // 1.通過JNDI查詢ConnectionFactory。JMS中連接工廠分QueueConnectionFactory和
?????????? // TopicConnectionFactory兩種,Weblogic不區(qū)分這兩種類型。
?????????? TopicConnectionFactory factory = (TopicConnectionFactory) ctx
????????????????? .lookup("ConnectionFactoryTest");
?
?????????? // 2.通過工廠建立連接connection
?????????? connection = factory.createTopicConnection();
?
?????????? // 3.創(chuàng)建session
?????????? session = connection.createTopicSession(false,
????????????????? TopicSession.AUTO_ACKNOWLEDGE);
?
?????????? // 4.創(chuàng)建Topic,必須新建一個Topic JNDI。
?????????? Topic topic = (Topic) ctx.lookup("TopicTest");
?
?????????? // 5.創(chuàng)建TopicPublisher
?????????? TopicPublisher tp = session.createPublisher(topic);
?
?????????? // 構造消息體
?????????? TextMessage tm = session.createTextMessage();
?????????? tm.setText("csdn tczxg");
?????????? tm.setStringProperty("user", "嘿嘿,JMS挺簡單的123。。。");
?
?????????? tp.publish(tm);
?
?????????? // 必須關閉連接
?????????? connection.close();
?
?
??????????? //接收者(訂閱者)部分代碼
ctx = new InitialContext();
?
?????????? // 1.通過JNDI查詢ConnectionFactory
?????????? TopicConnectionFactory factory = (TopicConnectionFactory) ctx
????????????????? .lookup("ConnectionFactoryTest");
?
?????????? // 2.通過工廠建立連接connection
?????????? connection = factory.createTopicConnection();
?
?????????? // 3.創(chuàng)建session
?????????? session = connection.createTopicSession(false,
????????????????? TopicSession.AUTO_ACKNOWLEDGE);
?
?????????? // 4.創(chuàng)建Topic
?????????? Topic topic = (Topic) ctx.lookup("TopicTest");
?
?????????? // 5.創(chuàng)建訂閱者
?????????? TopicSubscriber ts = session.createSubscriber(topic);
?
?????????? connection.start();
?
?????????? // 構造消息體
?????????? Message message = ts.receive();
?????????? if (message instanceof TextMessage) {
????????????? TextMessage tm = (TextMessage) message;
????????????? String user = tm.getStringProperty("user");
????????????? System.out.println(tm.getText() + ", user : " + user);
?????????? }
?????????? connection.close();
?
?
7.10 JTA(Java Transaction Architecture)
JTA定義了一種標準的API,應用系統(tǒng)由此可以訪問各種事務監(jiān)控。
?
7.11 JTS(Java Transaction Service)
JTS是CORBA OTS事務監(jiān)控的基本的實現。JTS規(guī)定了事務管理器的實現方式。該事務管理器是在高層支持Java Transaction API (JTA)規(guī)范,并且在較底層實現OMG OTS specification的Java映像。JTS事務管理器為應用服務器、資源管理器、獨立的應用以及通信資源管理器提供了事務服務。
?
7.12 JavaMail
JavaMail是用于存取郵件服務器的API,它提供了一套郵件服務器的抽象類。不僅支持SMTP服務器,也支持IMAP服務器。
?
7.13 JAF(JavaBeans Activation Framework)
JAF是一個專用的數據處理框架,它用于封裝數據,并為應用程序提供訪問和操作數據的接口。JAF的主要作用在于讓java應用程序知道如何對一個數據源進行查看、編輯和打印等操作。
7.14 webservice
Web Services是由企業(yè)發(fā)布的完成其特定商務需求的在線應用服務,其他公司或應用軟件能夠通過Internet來訪問并使用這項在線服務。
它是一種構建應用程序的普遍模型,可以在任何支持網絡通信的操作系統(tǒng)中實施運行;它是一種新的web 應用程序分支,是自包含、自描述、模塊化的應用,可以發(fā)布、定位、通過web調用。Web Service是一個應用組件,它邏輯性的為其他應用程序提供數據與服務.各應用程序通過網絡協(xié)議和規(guī)定的一些標準數據格式(Http,XML,Soap)來訪問Web Service,通過Web Service內部執(zhí)行得到所需結果.Web Service可以執(zhí)行從簡單的請求到復雜商務處理的任何功能。一旦部署以后,其他Web Service應用程序可以發(fā)現并調用它部署的服務。
XFire是新一代的Java Web服務引擎,XFire使得在JavaEE應用中發(fā)布Web服務變得輕而易舉。和其他Web服務引擎相比,XFire的配置非常簡單,可以非常容易地和Spring集成,它使得Java開發(fā)人員終于可以獲得和.Net開發(fā)人員一樣的開發(fā)效率。
舉例:首先應用相關的xfile的jar文件
1、Web.xml中配置
??? <servlet>
?????? <servlet-name>XFireServlet</servlet-name>
??? <servlet-class>org.codehaus.xfire.transport.http.XFireConfigurableServlet</servlet-class>
??? </servlet>
?
??? <servlet-mapping>
?????? <servlet-name>XFireServlet</servlet-name>
?????? <url-pattern>/servlet/XFireServlet/*</url-pattern>
??? </servlet-mapping>
?
??? <servlet-mapping>
?????? <servlet-name>XFireServlet</servlet-name>
?????? <url-pattern>/services/*</url-pattern>
</servlet-mapping>
2、service.xml中配置
<beans>
? <service xmlns="http://xfire.codehaus.org/config/1.0">
??? <name>SayHiService</name>
??? <namespace>http://cn.com.pansky/SayHiService</namespace>
??? <serviceClass>com.xfire.SayHiService</serviceClass>
??? <implementationClass>com.xfire.SayHiServiceImpl</implementationClass>
? </service>
</beans>
3、接口
public interface SayHiService {
??? public String sayHi(String name);
}
4、實現類
public class SayHiServiceImpl implements SayHiService {
??? @Override
??? public String sayHi(String name) {
?????? if (name == null) {
?????????? return "連名字也不肯告訴我嗎?";
?????? }
?????? return name + ", 你吃了嗎?沒吃回家吃去吧。";
??? }
?
??? public String 不告訴你() {
?????? return "我的名字不告訴你!";
??? }
}
5、客戶端調用類
public class tt {
?
??? /**
??? ?* @param args
??? ?*/
??? public static void main(String[] args) {
?????? String serviceURL = "http://localhost:8082/TestWebservice/services/SayHiService";
?????? Service serviceModel = new ObjectServiceFactory().create(
????????????? SayHiService.class, null, "http://cn.com.pansky/SayHiService",
????????????? null);
?
?????? XFireProxyFactory serviceFactory = new XFireProxyFactory();
?
?????? try {
?????????? SayHiService service = (SayHiService) serviceFactory.create(
????????????????? serviceModel, serviceURL);
?????????? Client client = Client.getInstance(service);
?????????? // client.addOutHandler(new OutHeaderHandler());
?
?????????? // disable timeout
?????????? client.setProperty(CommonsHttpMessageSender.HTTP_TIMEOUT, "1");
?
?????????? String hello = service.sayHi("張山瘋");
?????????? System.out.println("服務器對[張山瘋] 的回答是:" + hello);
?
?????????? hello = service.sayHi(null);
?????????? System.out.println("服務器胡言亂語說:" + hello);
?
?????? } catch (MalformedURLException e) {
?????????? e.printStackTrace();
?????? }
??? }
}
8、數據庫
8.1事務
8.1.1臟讀
臟讀又稱無效數據的讀出,是指在數據庫訪問中,事務T1將某一值修改,然后事務T2讀取該值,此后T1因為某種原因撤銷對該值的修改,這就導致了T2所讀取到的數據是無效的。臟讀就是指當一個事務正在訪問數據,并且對數據進行了修改,而這種修改還沒有提交到數據庫中,這時,另外一個事務也訪問這個數據,然后使用了這個數據。因為這個數據是還沒有提交的數據,那么另外一個事務讀到的這個數據是臟數據,依據臟數據所做的操作可能是不正確的。
?
8.1.2 更新丟失
第一類更新丟失(回滾丟失)
第二類更新丟失(覆蓋丟失)
兩個事務都同時更新一行數據,但是后來提交的事務所做的修改會覆蓋前面提交的事務的修改或者后面的事務回滾了前面的事務提交的數據,導致結果不是用戶想要的結果。這是因為系統(tǒng)沒有執(zhí)行任何的鎖操作,因此并發(fā)事務并沒有被隔離開來。
一、解決思路
基本兩種思路,一種是悲觀鎖,另外一種是樂觀鎖; 簡單的說就是一種(悲觀鎖)假定這樣的問題是高概率的,最好一開始就鎖住,免得更新老是失敗;另外一種(樂觀鎖)假定這樣的問題是小概率的,最后一步做更新的時候再鎖住,免得鎖住時間太長影響其他人做有關操作。
二、解決方案
1、悲觀鎖
a.傳統(tǒng)的悲觀鎖法(不推薦):
在彈出修改頁面初始化時(這種情況下一般會去從數據庫查詢出來),在這個初始化查詢中使用select ...for update nowait, 通過添加for update nowait語句,將這條記錄鎖住,避免其他用戶更新,從而保證后續(xù)的更新是在正確的狀態(tài)下更新的。然后在保持這個鏈接的狀態(tài)下,在做更新提交。當然這個有個前提就是要保持鏈接,就是要對鏈接要占用較長時間,這個在現在web系統(tǒng)高并發(fā)高頻率下顯然是不現實的。
b.現在的悲觀鎖法(推薦優(yōu)先使用):
在修改這個頁面做提交時先查詢下,當然這個查詢必須也要加鎖(select ...for update nowait),有人會說,在這里做個查詢確認記錄是否有改變不就行了嗎,是的,是要做個確認,只是你不加for update就不能保證你在查詢到更新提交這段時間里這條記錄沒有被其他會話更新過,所以這種方式也需要在查詢時鎖定記錄,保證在這條記錄沒有變化的基礎上再做更新,若有變化則提示告知用戶。?
2、樂觀鎖
a.舊值條件(前鏡像)法:
就是在sql更新時使用舊的狀態(tài)值做條件,SQL大致如下 Update table set col1 = newcol1value, col2 = newcol2value…. where col1 = oldcol1value and col2 = oldcol2value….,在上面的例子中我們就可以把當前工資作為條件進行更新,如果這條記錄已經被其他會話更新過,則本次更新了0行,這里我們應用系統(tǒng)一般會做個提示告知用戶重新查詢更新。這個取哪些舊值作為條件更新視具體系統(tǒng)實際情況而定。(這種方式有可能發(fā)生阻塞,如果應用其他地方使用悲觀鎖法長時間鎖定了這條記錄,則本次會話就需要等待,所以使用這種方式時最好統(tǒng)一使用樂觀鎖法。)
b.使用版本列法(推薦優(yōu)先使用):
其實這種方式是一個特殊化的前鏡像法,就是不需要使用多個舊值做條件,只需要在表上加一個版本列,這一列可以是NUMBER或?DATE/TIMESTAMP列,加這列的作用就是用來記錄這條數據的版本(在表設計時一般我們都會給每個表增加一些NUMBER型和DATE型的冗余字段,以便擴展使用,這些冗余字段完全可以作為版本列用),在應用程序中我們每次操作對版本列做維護即可。在更新時我們把上次版本作為條件進行更新。
綜上所述,我們對丟失更新問題建議采取上面的悲觀鎖b方法或樂觀鎖b方法(藍色字體已標注),其實這兩種方式的本質都一樣,都是在更新提交時做一次查詢確認在更新提交,我個人覺得都是樂觀的做法,區(qū)別在于悲觀鎖b方法是通過select..for update方式,這個可能會導致其他會話的阻塞,而樂觀鎖b方法需要多一個版本列的維護。
個人建議:在用戶并發(fā)數比較少且沖突比較嚴重的應用系統(tǒng)中選擇悲觀鎖b方法,其他情況首先樂觀鎖版本列法。
8.1.3 不可重復讀
一個事務對同一行數據重復讀取兩次,但是卻得到了不同的結果。它包括以下情況:
(1) 事務T1讀取某一數據后,事務T2對其做了修改,當事務T1再次讀該數據時得到與前一次不同的值。
(2) 幻讀(Phantom Reads):事務在操作過程中進行兩次查詢,第二次查詢的結果包含了第一次查詢中未出現的數據或者缺少了第一次查詢中出現的數據(這里并不要求兩次查詢的SQL語句相同)。這是因為在兩次查詢過程中有另外一個事務插入數據或刪除數據造成的。
8.1.4 解決方案
為了避免上面出現的幾種情況,在標準SQL規(guī)范中,定義了4個事務隔離級別,不同的隔離級別對事務的處理不同。
8.1.5未授權讀取
也稱為讀未提交(Read Uncommitted):允許臟讀取,但不允許更新丟失。如果一個事務已經開始寫數據,則另外一個數據則不允許同時進行寫操作,但允許其他事務讀此行數據。該隔離級別可以通過“排他寫鎖”實現。
8.1.6授權讀取
也稱為讀提交(Read Committed):允許不可重復讀取,但不允許臟讀取。這可以通過“瞬間共享讀鎖”和“排他寫鎖”實現。讀取數據的事務允許其他事務繼續(xù)訪問該行數據,但是未提交的寫事務將會禁止其他事務訪問該行。
8.1.7可重復讀取
可重復讀取(Repeatable Read):禁止不可重復讀取和臟讀取,但是有時可能出現幻影數據。這可以通過“共享讀鎖”和“排他寫鎖”實現。讀取數據的事務將會禁止寫事務(但允許讀事務),寫事務則禁止任何其他事務。
8.1.8序列化
序列化(Serializable):提供嚴格的事務隔離。它要求事務序列化執(zhí)行,事務只能一個接著一個地執(zhí)行,但不能并發(fā)執(zhí)行。如果僅僅通過“行級鎖”是無法實現事務序列化的,必須通過其他機制保證新插入的數據不會被剛執(zhí)行查詢操作的事務訪問到。
隔離級別越高,越能保證數據的完整性和一致性,但是對并發(fā)性能的影響也越大。對于多數應用程序,可以優(yōu)先考慮把數據庫系統(tǒng)的隔離級別設為Read Committed。它能夠避免臟讀取,而且具有較好的并發(fā)性能。盡管它會導致不可重復讀、虛讀和第二類丟失更新這些并發(fā)問題,在可能出現這類問題的個別場合,可以由應用程序采用悲觀鎖或樂觀鎖來控制。
?
| 隔離級別 | 更新丟失 ? | 臟讀取 | 重復讀取 | 幻讀 |
| 未授權讀取(排他寫鎖) | N | Y | Y | Y |
| 授權讀取(瞬間共享讀鎖、排他寫鎖) | N | N | Y | Y |
| 可重復讀取(共享讀鎖、排他寫鎖) | N | N | N | Y |
| 串行(行級鎖) | N | N | N | N |
8.1.9事務的四個屬性
原子性(atomicity)、一致性(consistency)、隔離性(isolation)和持久性(durability)。
8.2 鎖機制
8.2.1簡介
在數據庫中有兩種基本的鎖類型:排它鎖(Exclusive Locks,即X鎖)和共享鎖(Share Locks,即S鎖)。當數據對象被加上排它鎖時,其他的事務不能對它讀取和修改。加了共享鎖的數據對象可以被其他事務讀取,但不能修改。數據庫利用這兩種基本的鎖類型來對數據庫的事務進行并發(fā)控制。
8.2.2類型
根據保護的對象不同,Oracle數據庫鎖可以分為以下幾大類:DML鎖(data locks,數據鎖),用于保護數據的完整性;DDL鎖(dictionary locks,字典鎖),用于保護數據庫對象的結構,如表、索引等的結構定義;內部鎖和閂(internal locks and latches),保護 數據庫的內部結構。
DML鎖的目的在于保證并發(fā)情況下的數據完整性,。在Oracle數據庫中,DML鎖主要包括TM鎖和TX鎖,其中TM鎖稱為表級鎖,TX鎖稱為事務鎖或行級鎖。
當Oracle 執(zhí)行DML語句時,系統(tǒng)自動在所要操作的表上申請TM類型的鎖。當TM鎖獲得后,系統(tǒng)再自動申請TX類型的鎖,并將實際鎖定的數據行的鎖標志位進行置位。這樣在事務加鎖前檢查TX鎖相容性時就不用再逐行檢查鎖標志,而只需檢查TM鎖模式的相容性即可,大大提高了系統(tǒng)的效率。TM鎖包括了SS、SX、S、X 等多種模式,在數據庫中用0-6來表示。不同的SQL操作產生不同類型的TM鎖。
在數據行上只有X鎖(排他鎖)。在 Oracle數據庫中,當一個事務首次發(fā)起一個DML語句時就獲得一個TX鎖,該鎖保持到事務被提交或回滾。當兩個或多個會話在表的同一條記錄上執(zhí)行 DML語句時,第一個會話在該條記錄上加鎖,其他的會話處于等待狀態(tài)。當第一個會話提交后,TX鎖被釋放,其他會話才可以加鎖。
當Oracle數據庫發(fā)生TX鎖等待時,如果不及時處理常常會引起Oracle數據庫掛起,或導致死鎖的發(fā)生,產生ORA-60的錯誤。這些現象都會對實際應用產生極大的危害,如長時間未響應,大量事務失敗等。
8.2.3悲觀封鎖和樂觀封鎖
一、悲觀封鎖
鎖在用戶修改之前就發(fā)揮作用:
Select ..for update(nowait)
Select * from tab1 for update
用戶發(fā)出這條命令之后,oracle將會對返回集中的數據建立行級封鎖,以防止其他用戶的修改。
如果此時其他用戶對上面返回結果集的數據進行dml或ddl操作都會返回一個錯誤信息或發(fā)生阻塞。
二、樂觀鎖
樂觀的認為數據在select出來到update進取并提交的這段時間數據不會被更改。這里面有一種潛在的危險就是由于被選出的結果集并沒有被鎖定,是存在一種可能被其他用戶更改的可能。因此Oracle仍然建議是用悲觀封鎖,因為這樣會更安全。
8.2.3 DML鎖分類表
?
| 表1 Oracle的TM鎖類型 | |||
| 鎖模式 | 鎖描述 | 解釋 | SQL操作 |
| 0 | none | ? | ? |
| 1 | NULL | 空 | Select |
| 2 | SS(Row-S) | 行級共享鎖,其他對象只能查詢這些數據行 | Select for update、Lock for update、Lock row share |
| 3 | SX(Row-X) | 行級排它鎖,在提交前不允許做DML操作 | Insert、Update、Delete、Lock row share |
| 4 | S(Share) | 共享鎖 | Create index、Lock share |
| 5 | SSX(S/Row-X) | 共享行級排它鎖 | Lock share row exclusive |
| 6 | X(Exclusive) | 排它鎖 | Alter table、Drop able、Drop index、Truncate table 、Lock exclusive |
?
8.2.4數據庫封鎖方式
1、內部級封鎖
內部級封鎖是用于保護ORACLE內部結構,由系統(tǒng)內部實現,用戶不能訪問,因此我們不必對此做過多的了解。
?
2、DDL級封鎖(字典/語法分析封鎖)
DDL級封鎖也是由ORACLE RDBMS來控制,它用于保護數據字典和數據定義改變時的一致性和完整性。它是系統(tǒng)在對SQL定義語句作語法分析時自動地加鎖,無需用戶干予。字典/語法分析封鎖共分三類:
(1)、字典操作鎖:用于對字典操作時,鎖住數據字典,此封鎖是獨占的,從而保護任何一個時刻僅能對一個字典操作。
(2)、字典定義鎖:用于防止在進行字典操作時又進行語法分析,這樣可以避免在查詢字典的同時改動某個表的結構。
(3)、表定義鎖:用于 一個SQL語句正當訪問某個表時,防止字典中與該表有關的項目被修改。
?
3、DML級封鎖
DML級封鎖用于控制并發(fā)事務中的數據操縱,保證數據的一致性和完整性,其封鎖對象可以是表或行。
對用戶的數據操縱,Oracle可以自動為操縱的數據進行封鎖,但如果有操縱授權,則為滿足并發(fā)操縱的需要另外實施封鎖。DML封鎖可由一個用戶進程以顯式的方式加鎖,也可通過某些SQL語句隱含方式實現。
?
DML鎖有如下三種封鎖方式:
(1)、共享封鎖方式(SHARE)
(2)、獨占封鎖方式(EXCLUSIVE)
(3)、共享更新封鎖(SHARE UPDATE)
?
1、共享方式的表封鎖
共享方式的表封鎖是對表中的所有數據進行封鎖,該鎖用于保護查詢數據的一致性,防止其它用戶對已封鎖的表進行更更新。其它用戶只能對該表再施加共享方式的鎖,而不能再對該表施加獨占方式的封鎖,共享更新鎖可以再施加,但不允許持有共享更新封鎖的進程做更新。共享該表的所有用戶只能查詢表中的數據,但不能更新。
?
2、獨占方式表封鎖
獨占方式表封鎖是用于封鎖表中的所有數據,擁有該獨占方式表封鎖的用戶,即可以查詢該表,又可以更新該表,其它的用戶不能再對該表施加任何封鎖(包括共享、獨占或共享更新封鎖)。其它用戶雖然不能更新該表,但可以查詢該表。
3、共享更新封鎖方式
共享更新封鎖是對一個表的一行或多行進行封鎖,因而也稱作行級封鎖。表級封鎖雖然保證了數據的一致性,但卻減弱了操作數據的并行性。行級封鎖確保在用戶取得被更新的行到該行進行更新這段時間內不被其它用戶所修改。因而行級鎖即可保證數據的一致性又能提高數據操作的迸發(fā)性。
?
?
9、SOAP
9.1 簡介
SOAP:簡單對象訪問協(xié)議,簡單對象訪問協(xié)議(SOAP)是一種輕量的、簡單的、基于 XML 的協(xié)議,它被設計成在 WEB 上交換結構化的和固化的信息。 SOAP 可以和現存的許多因特網協(xié)議和格式結合使用,包括超文本傳輸協(xié)議( HTTP),簡單郵件傳輸協(xié)議(SMTP),多用途網際郵件擴充協(xié)議(MIME)。它還支持從消息系統(tǒng)到遠程過程調用(RPC)等大量的應用程序。
?
SOAP 包括四個部分:
SOAP 封裝:它定義了一個框架 , 該框架描述了消息中的內容是什么,誰應當處理它以及它是可選的還是必須的。
SOAP 編碼規(guī)則:它定義了一種序列化的機制,用于交換應用程序所定義的數據類型的實例。
SOAP RPC 表示:它定義了用于表示遠程過程調用和應答的協(xié)定。
SOAP 綁定:定義了一種使用底層傳輸協(xié)議來完成在節(jié)點間交換SOAP封裝的約定。
?
SOAP 消息基本上是從發(fā)送端到接收端的單向傳輸,但它們常常結合起來執(zhí)行類似于請求 / 應答的模式。所有的 SOAP 消息都使用 XML 編碼。一條 SOAP 消息就是一個包含有一個必需的 SOAP 的封裝包,一個可選的 SOAP 標頭和一個必需的 SOAP 體塊的 XML 文檔。
?
?
協(xié)議結構
SOAP 消息格式:
SOAP 標頭
<SOAP-ENV: Envelope? Attributes>
<SOAP-ENV:Body Attributes>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
目前主要在web服務中運用。
?????? 如:
<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <funName xmlns="http://tempuri.org/"> <parm1>value1</parm1> <parm2>value2</parm2> </funName> </soap:Body> </soap:Envelope>?
?
?
SOAP 通訊協(xié)議使用 HTTP 來發(fā)送XML 格式的信息。HTTP與RPC 的協(xié)議很相似,它簡單、 配置廣泛,并且對防火墻比其它協(xié)議更容易發(fā)揮作用。HTTP 請求一般由 Web 服務器軟件(如 IIS 和Apache)來處理, 但越來越多的應用服務器產品正在支持HTTP。XML 作為一個更好的網絡數據表達方式( NDR)。SOAP 把 XML 的使用代碼化為請求和響應參數編碼模式, 并用HTTP 作傳輸。具體地講, 一個SOAP 方法可以簡單地看作遵循SOAP編碼規(guī)則的HTTP請求和響應, 一個 SOAP 終端則可以看作一個基于HTTP 的URL, 它用來識別方法調用的目標。像CORBA/ IIOP一樣, SOAP不需要具體的對象綁定到一個給定的終端, 而是由具體實現程序來決定怎樣把對象終端標識符映像到服務器端的對象。
?
SOAP是一種基于XML的協(xié)議,它用于在分布式環(huán)境中發(fā)送消息,并執(zhí)行遠程過程調用。使用SOAP,不用考慮任何特定的傳輸協(xié)議(盡管通常選用HTTP協(xié)議), 就能使數據序列化。用SOAP來構建平臺與語言中性的互操作系統(tǒng)是一個好的選擇。總之,SOAP和 Web服務已為在XML上構建分布式應用程序基礎結構所需的一切都考慮好了。通過解決COM和Java組件對象模型之間的沖突,SOAP把多個平臺在訪問數據時所出現的 不兼容性問題減至最少。
?
?
10、終結面試
10.1基礎面試題
10.1.1、forward和redirect的區(qū)別
forward僅是容器中控制權的轉向,在客戶端瀏覽器地址欄中不會顯示出轉向后的地址;
redirect則是完全的跳轉,瀏覽器將會得到跳轉的地址,并重新發(fā)送請求鏈接。這樣,從瀏覽器的地址欄中可以看到跳轉后的鏈接地址。
所以,forward更加高效,在forward可以滿足需要時,盡量使用forward()方法,并且,這樣也有助于隱藏實際的鏈接。
?
轉載于:https://www.cnblogs.com/ZRJ-boke/p/5847123.html
總結
以上是生活随笔為你收集整理的java全面的知识体系结构总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (王道408考研数据结构)第八章排序-第
- 下一篇: 不定长内存池之apr_pool