傳智播客JavaWeb聽課總結

1、 JavaWeb基礎javascript

第一天:css

1.Eclipse詳解:html

(1).Bad versionnumber in .class file:編譯器版本和運行(JRE)版本不符合。高的JRE版本兼容低版本的編譯器版本。前端

(2).當程序有錯誤的時候,使用Debug as 運行程序。雙擊語句設置斷點。程序運行到此處中止。點擊跳入方法的內部代碼。點擊跳過,執行下一條代碼,點擊跳出,跳出方法。觀察變量的值,選中變量右擊 選擇watch. 跳入下一個斷點。查看斷點,調試完後必定要清除斷點。結束運行斷點的jvm.java

2.HashSet和hashCode和equals方法node

java系統首先調用對象的hashCode()方法得到該對象的哈希嗎,而後根據哈希嗎找到相應的存儲區域,最後取出該存儲區域內的每一個元素與該 元素進行比較.兩個equals相等,hashCode()相等。須要重寫equals,hashCode()方法.更改數據的值,hashCode() 的值也更改了,並未刪除.內存泄露.有個東西不在被用,可是未被刪除,致使內存泄露.mysql

3.Junit測試框架程序員

(1).在測試類,方法前加註解:@Test,否則出現初始化異常。web

(2).方法before,after前加@Before,@After註解。在測試方法以前和以後運行方法。正則表達式

(3).靜態方法beforeClass,afterClass方法前加上註解@BeforeClass,@AfterClass,類加載的時候運行

(4).Assert斷言。判斷兩個對象是否相等。指望值和實際值相等。

4.獲得配置文件的路徑

經過類加載器 reflect.class.getClassLoader.getResourceAsStream();在class指定目錄下查找指定的類文件進行 加載.編譯器把src中的.java文件編譯成class文件,全部非.java文件,原封不動的搬過去.可是這種方法是隻讀的.

經過類的信息reflect.class.getResourceAsStream();相對路徑

通常用絕對路徑,使用配置文件告訴用戶路徑.

必定要記住要用完整的路徑,可是完整的路徑不是硬編碼的,是計算出來的.

5.反射

(1).反射主要用於框架開發

(2).一個類有多個組成部分,例如:成員變量,方法,構造方法等,反射就是加載類,並解析類的各個組成部分。

(3).加載類使用Class.forName()靜態方法,給類的完整名稱,包名和類名。

(4).Class提供瞭解析public的構造方法,方法,字段等方法以及private。字段封裝數據,方法執行功能

(5).靜態方法無需傳遞對象,method.invoke()

(6).升級時保持兼容性,main函數的解析有點麻煩,反射解析數組參變量的時候的問題。啓動Java程序的main方法的參數是一個字符串數 組,即public static void main(String[] args),經過反射方式來調用這個main方法時,如何爲invoke方法傳遞參數呢?按照jdk1.5的語法,整個數組是一個參數,而按照 jdk1.4的語法,數組中的每一個元素對應一個參數,當把一個字符串數組做爲參數傳遞給invoke方法時,javac會到底按照哪一種語法進行處理 呢?jdk1.5確定要兼容jdk1.4的語法,會按jdk1.4的語法進行處理,即把數組打散成若干個單獨的參數。因此,在給main方法傳遞參數時, 不能使用代碼mainMethod.invoke(null,newString[]{"xxx"}),javac只把它當作jdk1.4的語法進行理 解,而不把它當作jdk1.5的語法解釋,所以會出現參數類型不對的問題。解決的方法:

mainMethod.invoke(null,newObject[]{new String[]{"xxx"}});

mainMethod.invoke(null,(Object)newString[]{"xxx"});編譯器會作特殊處理,編譯時不把參數當作數組看待,也就不會把數組打散成若干個參數了.

(7).對數組進行反射:相同的維數(不是數組元素的個數,例如都是一維數組,不關心數組的大小),相同的8種基本數據類型時數組有相同的字節碼.

6. 泛型

(1).泛型是對象類型,不能是基本類型,泛型存在源代碼級別上,給編譯器看的,生成class文件就不存在泛型了

(2).參數類型變量,實際類型變量,泛型類型,參數化的類型

(3).自定義泛型方法:public void method(T args){};public<T,K,V> void method(T a,K b,V c){};

(4).靜態方法public static void method(T t){};泛型類不做用靜態方法

7.可變參數

(1).可變參數就當作數組,能夠使用加強for循環

(2).可變參數列表爲最後一個參數

(3).能夠給可變參數傳遞一個數組

(4).可變參數的類型是基本類型仍是對象類型

8.課程介紹

(1).在谷歌心目中,「雲」必須具有如下條件:數據都存在網上,而非終端裏,軟件最終消失,只要你的「雲」設備擁有瀏覽器就能夠運行如今的一切, 「雲」時代的互聯網終端設備將不只僅是PC,手機,汽車,甚至手錶,只要有簡單的操做系統加個瀏覽器就徹底能夠實現,因爲數據都在「雲」端,企業的IT管 理愈來愈簡單,企業和我的用戶也不一樣在擔憂病毒,數據丟失等問題。

(2).李開復描述了這樣一個場景,只要你的PC或手機等終端裏安裝了一個簡單的操做系統和完整功能的瀏覽器,開機後輸入本身的用戶名和密碼,你存在「雲」中的應用軟件和數據就會同步到終端裏。

9.快捷鍵

(1).配置快捷鍵:window->preferences->key

(2).Alt+/ :內容提示

Ctrl+1 :快速修復

      Ctrl+Shift+O :快速導入包

      Ctrl+Shift+F :格式化代碼

      Alt+方向鍵 :跟蹤代碼

      Ctrl+Shift+/ :添加註釋

      Ctrl+Shift+\ :取消註釋

      Ctrl+Shift+X :更改成大寫

      Ctrl+Shift+Y :更改成小寫

      Ctrl+Shift+向下鍵 :複製代碼

      Ctrl+Shift+向上,向下  :改變代碼行的順序

      Ctrl+T  :查看繼承關係

      Ctrl+Shift+T :查看源代碼

      Ctrl+Shift+L :查看全部的快捷鍵

10.類加載器及其委託機制的深刻分析

(1).Java虛擬機中能夠安裝多個類加載器,系統默認三個主要類加載器,每一個類負責加載特定位置的類:BootStrap,ExtClassLoader,AppClassLoader

(2).類加載器也是Java類,由於其餘java類的加載器自己也要被類加載器加載,顯然必須有第一個類加載器不是java類,這正是BootStrap(內嵌到JVM的內核中,使用C++語言編寫的)

(3).Java虛擬機中的全部類裝載器採用具備父子關係的屬性結構進行組織,在實例化每一個類轉載器對象時,須要爲其指定一個父級類裝載器對象或者默認採用系統類裝載器爲其父級類加載器

(4).

public class ClassLoaderTest{

public static void main(String[] args){

System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());

//輸出爲sun.misc.Lanuncher$AppClassLoader;

System.out.println(System.class.getClassLoader());

//輸出爲null,由於類System是由BootStrap加載的;

}

}

(5).BootStrap->ExtClassLoader->AppClassLoader

ClassLoader loader= ClassLoaderTest.class.getClassLoader();

while(loader!=null){

System.out.println(loader.getClass().getName());

loader = loader.getParent();//往上順序打印

}

System.out.println(loader);//最後打印老祖宗

(6).

BootStrap------>JRE/lib/rt.jar

ExtClassLoader----->JRE/lib/ext/*.jar

AppClassLoader------>ClassPath指定的全部jar或目錄

用Eclipse的打包工具將ClassLoaderTest打包成itcast.jar,而後放在jre/lib/ext目錄下,在 eclipse中運行這個類,運行結果顯示爲ExtClassLoader,此時的環境狀態是classpath目錄有 ClassLoaderTest.class,ext/itcast.jar包中也有ClassLoaderTest.class,這時咱們在打印 ClassLoaderTest類的類加載名稱,發現是ExtClassLoader,而不是AppClassLoader.

(7).類加載的委託機制:

當Java虛擬機要加載一個類時,到底派出哪一個類加載器去加載呢:

首先當前線程的類加載器去加載線程中的第一個類

若是類A中引用了類B,Java虛擬機將使用加載類A的類加載器來加載類B

還能夠直接調用ClassLoader.loadClass()方法來指定某個類加載器去加載某個類

每一個類加載器加載類時,又先委託給其上級類加載器

當全部祖宗類加載器沒有加載到類,回到發起者類加載器,還加載不了,則拋ClassNotFoundException,不是再去找發起者類加載器的兒子,由於沒有getChild方法,即便有,那麼多個兒子,找哪個呢?

對着類加載器的層次結構圖和委託加載原理

(8).Thread類有一個方法setContextClassLoader(ClassLoader classLoader)//加載當前的類.

(9).每一個類加載都首先會委託送到BootStrap,那麼BootStrap很累,這樣,那爲何很少搞幾個BootStrap呢,之因此不這 樣作,是由於,便於統一管理,由於全部的類都會找BootStrap,可能這時有幾個相同的類進行加載,那麼BootStrap,不會屢次將他們的 class文件加載內存中,只會加載一份便可.這樣效率就高了.

(10).

public class MyClassLoader{

public static void main(String[]args){

String srcPath=args[0];

String destDir=args[1];//獲得目錄

String destFileName =srcPath.substring(srcPath.lastIndexOf('/')+1);//獲得文件名

String destFilePath=destDir+"\"+destFileName;

FileInputStream fis = newFileInputStream(srcPath);

FileOutputStream fos=new FileOutputStream(destPath);

cypher(fis,fos);

fis.close();

fos.close();

}

private static void cyp(InputStreamips,OutputStream ops){

int b =-1;

while((b=ips.read())!=-1){

ops.write(b^0xff);//對內容進行異或處理

}

}

}

class ClassLoader extends Date{

public String toString(){

return "hello,itcast";

}

}

args[0]:ClassLoader.class的絕對路徑

args[1]:itcastlib

有包名的類不能調用無包名的類.

(11).編寫本身的類加載器:

知識講解:

自定義的類加載器必須繼承ClassLoader(抽象類)

覆蓋findClass方法

defineClass方法:獲得class文件轉換成字節碼

編程步棸:

編寫一個文件內容進行簡單加密的程序

編寫了一個本身的類加載器,可實現對加密過的類進行裝載和解密

編寫一個程序調用類加載器加載類,在源程序中不能用該類名定義引用變量,由於編譯器沒法識別這個類,程序中能夠出了使用ClassLoader.load方法以外,還能夠使用設置線程的上下文類加載器或者系統類加載器,而後再使用Class.forName

(12).

模板設計模式:

父類--->loadClass(相同的)

子類1(本身乾的)

子類2(本身乾的)

覆蓋findClass方法(本身幹)

(13).

public class MyClassLoader extendsClassLoader{

public MyClassLoader(){

}

public MyClassLoader(String classDir){

this.classDir = classDir;

}

@Override

protected Class<?> findClass(Stringname){

String classFileName = classDir +"\" + name + ".class";

FileInputStream fis = new FileInputStream(classFileName);

ByteArrayOutputStream bos = newByteArrayOutputStream();

cypher(fis,bos);

fis.close();

byte[] bytes = bos.toByteArray();

defineClass(bytes,0,bytes.length);

return super.findClass(name);

}

public static void main(String[] args){

Class clazz = newMyClassLoader("itcastlib").loadClass("ClassLoaderAttachment");

ClassLoaderAttachment d1 =clazz.newInstance();

}

}

(14).windows->showview->problem查看錯誤.

(15).能夠查看Servlet的類加載委託繼承樹

11. 枚舉

(1).枚舉的做用限定指定的值,沒有枚舉前設計一個類,將構造函數設置成私有的,變量設置成靜態常量

(2).枚舉能夠有構造函數(私有的),字段,方法

(3).能夠定義set,get方法,獲取變量的值。

(4).帶有抽象方法的枚舉,不能new出新的對象了。在new對象的時候就重寫抽象方法,使用匿名內部類

(5).枚舉中的每一個枚舉值表明枚舉類的一個對象。

(6).枚舉也能夠實現接口,或繼承抽象類

(7).JDK5中的switch拓展爲除了接受int,short,char,byte外,也能夠接受枚舉類型。

(8).枚舉的方法,name,ordial,valueOf,將字符串轉換成枚舉值。表單提交數據的時候。values返回枚舉的全部的枚舉值

12.內省

(1).內省:Introspector,專門操做Bean的屬性。

(2).Bean的屬性:只有字段提供了set/get方法,就是屬性。只要有get/set的方法,就有一個屬性,因此屬性是有get/set方法決定的

(3).任何類都繼承了Object類,又由於Object中有一個class屬性

(4).內省的入口類:Introspector,方法getPropertyDescriptors()獲取Bean的屬性

(5).操做Bean的指定屬性

(6).BeanUtils框架操做Bean

(7).在工程中新建一個文件夾,將架包複製到文件夾中,還需另外的架包loging,選中架包,右擊build path加入到工程的環境中

(8).BeanUtils使用方便,類型自動轉化,只支持8中基本數據類型

(9).給BeanUtils註冊類型轉換器,ConvertUtils.register()

(10).將Map中的數據整合到對象中,BeanUtils.populate()方法

13.配置Java模板代碼

window->preferences->java->Editor->Template:編輯模板代碼:line_selection,光標cursor,右擊選擇source with

14.享元模式

相同的對象只實例化一個,實例:桌面上的圖標,word中字符,有不少小的對象,有不少相同的屬性,不一樣的屬性叫作外部行爲,相同的屬性叫作內部行爲integer的緩衝池

15.註解

(1).@SuppressWarning("deprecation")過期註解

(2).@Deprecated註解,表示該方法是否過期,架包升級時添加的註解

(3).註解至關於一種標記,經過反射了解你的類及各類元素上有無何種標記

(4).註解至關於一個類:@interface Annotation{};註解類,應用註解類的類,對應用了註解類的類進行反射操做的類

(5).AnnotationTest.class.getAnnotation(ItcastAnnotation.class)獲得類AnnotationTest上的註解ItcastAnnotation,註解上使用註解叫作元註解,元數據,元信息

(6).@Retention(RetentionPolicy.RUNTIME)(保持到運行階段),@Retention(RetentionPolicy.SOURCE)(保持在源文件階 段),@Retention(RetentionPolicy.CLASS)(保持在class文件中):源代碼->class文件->(類加載)內存中的文件(字節碼)

(7).@Override註解保持到SOURCE,@SuppressWarning註解保持到SOURCE,@Deprecated註解保持到RUNTIME(只有將該類調到內存中才知道該類中的方法是否過期了)

(8).@Target({ElementType.METHOD,ElementType.TYPE})註解只能標記到方法上或類,接口等類型上 (9).註解的屬性:String color();類有個color屬性,還有一個特殊的屬性value,屬性的默認值default,數組的屬性值,枚舉的屬性值,註解的屬性值

次日:

1.dom4j解析XML文檔

(1).Dom4j是一個簡單、靈活的開放源代碼的庫,Dom4j是由早期開發JDOM的人分離出來然後獨立開發的,與JDOM不一樣的是,dom4j使用接口和抽象基類,雖然Dom4j的api相對要複雜一些,可是他提供了比JDOM更好的靈活性

(2).Dom4j是一個很是優秀的Java XML API,具備性能優異、功能強大和極易使用的特色,如今不少軟件採用的Dom4j,例如hibernate,包括sun公司本身的JAXM也使用了Dom4j

(3).使用Dom4j開發,須要下載dom4j相應的jar文件

  1. XML語法

(1).編寫XML文檔時,須要先使用文檔聲明,聲明XML文檔的類型,使用IE校驗XML文檔的正確性.

(2).XML文檔中的"中國"保存爲本地的碼錶的"中國"

(3).在XML文檔中,空格和換行都做爲原始內容被處理

(4).XML區分大小寫,一個標籤能夠有多個屬性,每一個屬性都有它本身的名稱和取值,在XML技術中,

標籤屬性所表明的信息也能夠被表示子標籤表示

(5).XML文件中的註釋採用:"

在Eclipse中jsp是用UTF-8編碼存放的,當讀取jsp的內容時,是用本地字符編碼的,可能出現亂碼,因此要設置讀取文件的編碼集.

(6).瀏覽器重定向的JSP不能放在web-inf目錄中,而請求轉發的JSP能夠放在web-inf目錄中

(7).struts2中的全局視圖:

<resultname="index.jsp">

和struts1中的全局視圖是很類似的

咱們能夠定義一個包,而後將全局視圖的配置放到這個包中

5.struts2經常使用標籤

(1).property標籤用於輸出指定值:

<s:setname="name" value="kk"/>

<s:propertyvalue ="#name"/>

default:可選屬性,若是須要輸出的屬性值爲null,則顯示該屬性指定的值

escape:可選屬性,指定是否格式化HTML代碼

value:可選屬性,指定須要輸出的屬性值,若是沒有指定該屬性,則默認輸出ValueStack棧頂的值

id:可選屬性,指定該元素的標識

(2).iterator標籤用於對集合進行迭代,這裏的集合包含List、Set和數組

red blue >


value:可選屬性,指定被迭代的集合,若是沒有設置該屬性,則使用ValueStack棧頂的集合,

id:可選屬性,指定集合裏元素的id(已被標註爲過期)

status:可選屬性,該屬性指定迭代時的iteratorStatus實例,該實例包含以下幾個方法:

int getCount(),返回當前迭代了幾個元素

int getIndex(),返回當前迭代元素的索引

boolean isEven(),返回當前被迭代元素的索引是否爲偶數

boolean isOdd(),返回當前被迭代元素的索引是不是奇數

boolean isFirst(),返回當前被迭代元素是不是第一個元素

boolean isLast(),返回當前被迭代元素是不是最後一個元素

(3).<s:setname="age" value="21" scope="request"/>

<s:iftest="#request.age==23">

23

21

都不等

(4).url標籤:

生成相似以下路徑:

/struts/test/helloworld_add.action?persionid=3

當標籤的屬性值做爲字符串類型處理時,"%"符號的用途是計算OGNL表達式的值

輸出結果:

myurl

http://www.foshanshop.net

(5).表單標籤checkboxlist複選框

若是集合爲list

若是集合爲MAP

生成以下html代碼:

固然集合裏面存放的也能夠是對象類型

(6).單選框

6.struts2的處理流程與Action的管理方式

(1).用戶請求->(查看web.xml文 件)StrutsPrepareAndExecuteFilter->Interceptor(struts2內置的一些攔截器或用戶自定義攔截 器)->Action(用戶編寫的Action類,相似Struts1中的action,針對每一次請求,都建立一個 Action)->Result(相似struts1中的forward)->Jsp/html(響應)

(2).StrutsPrepareAndExecuteFilter是struts2框架的核心控制器,它負責攔截由 /"指定的全部用戶請求,當用戶請求到達時,該fileter會過濾用戶的請求,默認情 況下,若是用戶請求的路徑不帶後綴或者後綴以.action結尾,這時請求將被轉入到struts2框架處理,不然struts2框架將略過該請求的處 理,當請求轉入struts2框架處理時會先通過一系列的攔截器,而後再到Action,與struts1不一樣,struts2對用戶的每一次請求都會創 建一個Action,因此struts2中的action是線程安全的.

7.XML配置方式實現對action的全部方法進行校驗

(1).基於XML配置方式實現對action的全部方法進行輸入校驗:

使用基於XML配置方式實現輸入校驗時,Action也須要繼承ActionSupport,而且提供校驗文件,校驗文件和action類放在同一 個包下,文件的取名格式爲:ActionClassName-validation.xml,其中,ActionClassName爲action的簡單 類名,-validation爲固定寫法,若是Action類爲cn.itcast.UserAction,那麼該文件的取名應 爲:UserAction-validation.xml,下面是校驗文件的模板:

<field-validatortype="requiredstring">

<paramname="trim">true

用戶名不能爲空

指定action中要校驗的屬性, 指定校驗器,上面指定的校驗器 requirestring是由系統提供的,系統提供了能知足大部分驗證需求的校驗器,這些校驗器的定義能夠在xwork-2.x.jar中的 com.opensymphony.xwork2.validator.validators下的default.xml中找 到, 爲校驗失敗後的提示信息,若是須要國際化,能夠爲message指定key屬性,key的值爲資源文件中的key,在 這個校驗文件中,對action中字符串類型的username屬性進行驗證,首先要求調用trim()方法去掉空格,而後判斷用戶名是否爲空.

(2).struts2提供的校驗器列表:

required(必填校驗器,要求field的值不能爲Null)

requiredstring(必填字符串校驗器,要求field的值不能爲null,而且長度大於0,默認狀況下會對字符串取錢後空格)

stringlength(字符串長度校驗器,要求field的值必須在指定的範圍內,不然校驗失敗,minLength參數指定最小長度,maxLength參數指定最大長度,trim參數指定校驗field以前是否去除字符串先後的空格)

regex(正則表達式校驗器,檢查被校驗的field是否匹配一個正則表達式,expression參數指定正則表達式,caseSensitive參數指定進行正則表達式匹配時,是否區分大小寫,默認值爲true)

int(整數校驗器,要求field的整數值必須在指定範圍內,min指定最小值,max指定最大值)

double(雙精度浮點數校驗器,要求field的雙精度浮點數必須在指定範圍內,min指定最小值,max指定最大值)

fieldexpression(字段OGNL表達式校驗器,要求field知足一個OGNL表達式,expression參數指定OGNL表達式,該邏輯表達式基於ValueStack進行求值,返回true時校驗經過,不然不經過)

email(郵件地址校驗器,要求若是field的值非空,則必須是合法的郵件地址)

URL(網址校驗器,要求若是field的值非空,則必須是合法的URL地址)

date(日期校驗器,要求field的日期值必須在指定範圍內,min指定最小值,max指定最大值)

conversion(轉換校驗器,指定在類型轉換失敗時,提示的錯誤信息)

visitor(用於校驗action中的符合屬性,它指定一個校驗文件用於校驗符合屬性中的屬性)

expression(OGNL表達式校驗器,expression參數指定ognl表達式,該邏輯表達式基於ValueStack進行求值,返回true時校驗經過,不然不經過,該校驗器不可用在字段校驗器風格的配置中)

(3).[CDATA[文本內容]]:文本內容不會被解析,只會原封不動的當作文本處理

(4).編寫校驗文件時,不能出現幫助信息:

在編寫ActionClassName-validation.xml校驗文件時,若是出現不了幫助信息,能夠按照下面方式解決:

windows->preferences->myeclipse->filesand editors->xml->xmlcatalog:點擊add,在出現的窗口中的location中選"file system"而後再xwork-2.1.2戒菸目錄的src\java目錄中選擇xwork-validator-1.0.3.dtd,回到設置窗口的 時候,不要急着關閉窗口,應把窗口中的Key Type改成URI,Key改成http://www.opensymphoney.com/xwork/xwork-validaor-1.0.3.dtd

8.XML配置方式實現對action的指定方法校驗

(1).基於XML配置方式對指定action方法實現輸入校驗:

當校驗文件的取名爲ActionClassName-validation.xml時,會對action中的全部處理方法實施輸入校驗,若是你只需 要對action中的某個action方法實施校驗,那麼校驗文件的取名應爲:ActionClassName-ActionName- validation.xml,其中ActionName爲struts.xml中的action的名稱,例如:在實際應用中,常有如下配置:

<resultname="success">/WEB-INF/page/message.jsp

<resultname="input">/WEB-INF/page/addUser.jsp

UserAction中有如下兩個處理方法:

public String add() throws Exception{

}

public String update() throws Exception{

}

要對add()方法實施驗證,校驗文件的取名爲:UserAction-user_add-validation.xml

要對update()方法實施驗證,校驗文件的取名爲:UserAction-user_update-validation.xml

(2).基於XML校驗的一些特色:

當爲某個action提供了ActionClassName-validation.xml和ActionClassName-ActionName-validation.xml兩種規則的校驗文件時,系統按下面順序尋找校驗文件:

ActionClassName-validation.xml

ActionClassName-ActionName-validation.xml

系統尋找到第一個校驗文件時還會繼續搜索後面的校驗文件,當搜索到全部校驗文件時,會把校驗文件裏的全部校驗規則彙總,而後所有應用於action方法的校驗,若是兩個校驗文件中指定的校驗規則衝突,則只使用後面文件中的規則。

當action繼承了另外一個action,父類action的校驗文件會先被搜索到

假設UserAction繼承BaseAction

<actionname="user" class="cn.itcast.action.UserAction"method="{1}">

訪問上面的action,系統先搜索父類的校驗文件:BaseAction-validation.xml,BaseAction-user- validation.xml,接着搜索子類的校驗文件:UserAction-validation.xml,UserAction-user- validation.xml,應用於上面action的校驗規則爲這四個文件的總和

9.動態方法調用和使用通配符定義action

(1).在struts1中實現方法的動態調用:

<actionpath="/control/employee/manage" type="....DispatchAction"parameter="method"/>

/control/employee/manage?method=addUI

可是Action必須繼承DispatchAction

(2).在struts2中有兩種方式:

第一種:(struts2.1版本後就不建議使用了)是動態方法調用:若是Action中存在多個方法時,咱們能夠使用!+方法名調用指定方法,以下:

public class HelloWorldAction{

private String message;

....

public String execute()throws Exception{

this.message="個人第一個struts2應用";

}

public String other() throws Exception{

this.message="第二個方法";

return "success";

}

}

假設訪問上面的action的URL路徑爲:/struts/test/helloworld.action,要訪問action的other方 法,咱們就能夠這樣調用:/struts/test/helloworld!other.action,若是不想使用動態方法調用,咱們能夠經過常量 struts.enable.DynamicMethodInvocation關閉動態方法調用:

<constantname="struts.enable.DynamicMethodInvocation"value="false"/>

第二種:使用通配符定義action(推薦使用的)

<action name="helloworld_*"class="cn.itcast.action.HelloWorldAction" method="{1}>

<resultname="success">/WEB-INF/page/hello.jsp

public class HelloWorldAction{

private String message;

....

public String execute()throws Exception{

this.message="個人第一個struts2應用";

}

public String other() throws Exception{

this.message="第二個方法";

return "success";

}

}

要訪問other()方法,能夠經過這樣的URL訪問:/test/helloworld_other.action

name="helloworld_"後可根據多個,method={1},'1'表示匹配*的位置

name="helloworld_*_*",method={2}:要訪問other()方法,能夠經過這樣的URL訪問:/test/helloworld_xxx_other.action

10.對action指定的方法進行校驗

手工編寫代碼實現對action指定方法輸入校驗:

經過validateXxx()方法實現,validateXxx()只會校驗action中方法名爲Xxx的方法,其中Xxx的第一個字母要大 寫,當某個數據校驗失敗時,咱們應該調用addFieldError()方法往系統的fieldErrors添加校驗失敗信息,(爲了使用 addFieldError()方法,action能夠繼承ActionSupport(),若是系統的fieldErrors包含失敗信 息,struts2會將請求轉發到名爲input的result,在input視圖中能夠經過 顯示失敗信息.

validateXxx()方法使用例子:

public Stringadd() throws Exception{return "success";}

public voidvalidateAdd() {

if(username==null&&"".equals(username.trim()))this.addFieldError("username","用戶名不能爲空");

}

驗證失敗後,請求轉發至input視圖:<resultname="input">/WEB-INF/page/addUser.jsp

在addUser.jsp頁面中使用 顯示失敗信息

11.對Action中全部方法進行輸入校驗

(1).在struts2中,咱們能夠實現對action的全部方法進行校驗或者對action的指定方法進行校驗

(2).對於輸入校驗struts2提供了兩種實現方法:一種是採用手工編寫代碼實現,另外一種是基於XML配置方式實現

(3).手工編寫代碼實現對action中全部方法輸入校驗:經過重寫validate()方法實現,validate()方法會校驗action 中全部與execute方法簽名相同的方法,當某個數據校驗失敗時,咱們應該調用addFieldError()方法往系統的fieldErrors添加 校驗失敗信息(爲了使用addFieldError()方法,action能夠繼承ActionSupport(),若是系統的fieldErrors包 含失敗信息,struts2會將請求轉發到名爲input的result,在input視圖中能夠經過 顯示失 敗信息.

validate()使用例子:

public voidvalidate(){

if(this.mobile==null||"".equals(this.mobile.trim())) {this.addFieldError("username","手機號不能爲 空")}else{if(Pattern.compile("^1[358]\d{9}").matcher(this.mobile.trim()).matchers()) {this.addFieldError("mobile","手機號的格式不正確");}}

}

驗證失敗後,請求轉發至input視圖:

<resultname="input">/WEB-INF/page/addUser.jsp

在addUser.jsp頁面中使用 顯示失敗信息

12.多文件上傳

(1).多文件上傳,就是在一個文件上傳的基礎上,將屬性File變成數組類型File[]類型便可,同時該字段的名稱必需要和上傳頁面中屬性name的名稱同樣.

而後進行一次迭代,就能夠獲得全部的文件

13.防止表單重複提交

標籤防止表單重複提交

第一步:在表單中加入

<s:textfieldname="person.name"/>

第二步:

<interceptor-refname="defaultStack"/>

<interceptor-refname="token"/>

<resultname="invalid.token">/WEB-INF/page/message.jsp

/WEB-INF/page/result.jsp

以上配置加入了"token"攔截器和"invalid.token"結果,由於"token"攔截器在會話的tlent與請求的token不一致時,將會直接返回"invalid.token"結果

在debug狀態,控制檯出現下面信息,是由於Action中並無struts.token和struts.token.name屬性,咱們不用關心這個錯誤

使用了 標籤能夠不指定action的上下文標籤路徑,能夠經過命名空間實現.和前面的原理是同樣的,在路徑後面添加上sessionid號,只是這步操做不須要咱們本身獲得sessionid號,struts幫咱們操做.

在值棧中的對象,訪問無需添加'#'

14.訪問或添加幾個屬性

(1).訪問或添加request/session/application屬性,在struts2中的Action中的execute方法中沒有Servlet api(沒有響應的參數);

public String scope() throws Exception{

ActionContextctx=ActionContext.getContext();

ctx.getApplication().put("app","應用範圍");

ctx.getSession().put("ses","session範圍");

ctx.put("request","request範圍");

return "scope";

}

${applicationScope.app} ${sessionScope.ses} ${requestScope.req}

(2).獲取HttpServletRequest/HttpSession/ServletContext/HttpServletResponse對象:

方法一:經過ServletActionContext類直接獲取

public String rsa() throws Exception{

HttpServletRequest request =ServletActionContext.getRequest();

ServletContextservletContext=ServletContext.getServletContext();

request.getSession();

HttpServletResponseresponse=ServletActionContext.getResponse();

return "scope";

}

方法二:實現指定接口,由struts框架運行時注入:

public class HelloWorldAction implementsServletRequestAware,ServletResponseAware,ServletContextAware{

private HttpServletRequest request;

private ServletContext servletContext;

private HttpServletResponse response;

public voidsetServletRequest(HttpServletRequest req){

this.request.req;

}

public voidsetServletResponse(HttpServletResponse res){

this.response=res;

}

public voidsetServletContext(ServletContext ser){

this.servletContext=ser;

}

注意1和2的不一樣,一個不須要獲得對象,一個須要獲得對象,因此要區分兩個的應用場景

}

15.解決struts配置文件無提示問題

找到struts2.0.dtd文件便可,windows->preferences->MyEclipse->XML->XMLCatalog,點擊添加strut2.dtd

16.介紹struts2及struts2開發環境的搭建

(1).struts2是在webwork2基礎發展而來的,和struts同樣,struts2也屬於MVC框架,不過有一點你們須要注意的是: 儘管struts2和struts1在名字上的差異不是很大,可是struts2和struts1在代碼編寫分割上幾乎是不同的,那麼既然有了 struts1,爲什麼還要推出struts2,主要是由於有一下有點:

第一:在軟件設計上struts2沒有像struts1那樣跟Servlet api和struts api有着緊密的耦合,struts2的應用能夠不依賴於servlet api 和struts api,struts2的這種設計屬於無侵入式的設計,而struts1卻屬於侵入式設計,由於其的

execute()方法中的參數爲ActionMapping,ActionForm,HttpServletRequest,HttpServletResponse

第二:struts2提供了攔截器,利用攔截器能夠進行AOP編程,實現如權限攔截等功能

第三:struts2提供了類型轉換器,咱們能夠把特殊的請求參數轉換成須要的類型,在struts1中,若是咱們要實現一樣的功能,就必須向struts1的底層實現BeanUtils註冊類型轉換器才行

第四:struts2提供支持多種表現層技術,如:JSP,freeMarker,Velocity等

第五:struts2的輸入校驗能夠對指定方法進行校驗,解決了struts1長久之痛,struts1中的validate方法對全部的方法進行校驗

第六:提供了全局範圍、包範圍、和Action範圍的國際化資源文件管理實現.

(2).搭建struts2的環境和struts1是相同的,第一步導入相關包,第二步創建struts2的配置文件,第三步在web.xml中註冊struts2框架的配置

(3).所需的包:struts2-core-2.x.x.jar,xwork-2.x.x.jar(webwork的核心架包),ognl-2.6.x.jar

(4).struts2默認的配置文件爲struts.xml,該文件須要放在/web-inf/classes目錄下

(5).在struts1中,struts框架是經過servlet啓動的,在struts2中,struts框架是經過Filter啓動的,它在 web.xml中的配置以下所示:能夠參照struts文件夾下的例子中拷貝,在strutsperpareExecuteFilter的init()方 法中將會讀取類路徑下默認的配置文件struts.xml完成初始化操做,注意:struts2讀取到struts.xml的內容後,以javabean 形式存放在內存中,之後struts2對用戶的每次請求處理將使用內存中的數據,而不是每次都讀取struts.xml文件

(6).自從struts2.1.3之後,下面的FilterDispatcher已經標註爲過期了,struts2.1.3後期版本爲StrutsPrepareAndExecuteFilter類

17.開發第一個應用

(1).在struts.xml中的配置:

<actionname="helloworld" class="cn.itcast.action.HelloWorldAction"method="execute">

<resultname="success">/WEB-INF/page/hello.jsp

在struts2框架中使用包來管理Action,包的做用和Java中的類包是很是相似的,它主要用於管理一組業務功能相關的action,在實際應用中,咱們應該吧一組業務功能相關的Action放在同一個包下

配置包時必須指定name屬性,該name屬性能夠任意取名,但必須惟一,它不對應java的類包,若是其餘包要繼承該包,必須經過該屬性進行引 用,包的namespace屬性用於定義該報的命名空間,命名空間做爲訪問該包下Action的路徑的一部分,如訪問上面例子的Action,訪問路徑 爲:/test/helloworld.action,namespace屬性能夠不配置,對本例而言,若是不指定該屬性,默認的命名空間爲" "(空字符串).固然配置能夠減小重複的代碼,struts1中的重複代碼就能夠使用命名空間來解決

一般每一個包都應該繼承struts-default包,由於struts2不少核心的功能都是攔截器來實現的,如:從請求中把請求參數封裝轉到 action、文件上傳和數據驗證等都是經過攔截器實現的,struts-defaul定義了這些攔截器和Result類型,能夠這麼說:當包繼承了 struts-default才能使用struts2提供的核心功能,struts-default包是在struts2-core-2.x.x.jar 文件中的struts-default.xml中定義,struts-default.xml也是struts2默認配置文件,struts2每次都會自 動加載struts-default.xml文件,包還能夠經過abstract="true"定義爲抽象包,抽象包中不能包含action,能夠查看 struts-default.xml文件中,就能夠看到定義了不少攔截器

和struts1中的forward很類似,定義視圖

(2).public Stringexecute(){return 視圖的名稱;}注意到這個方法和struts1不一樣,沒有參數,返回類型也不一樣,這就下降了耦合性,非侵入式的編程了.

(3).在jsp中使用el表達式便可${message},message是Action中的一個方法getMessage()方法,而不是根據Action中的成員變量message

18.配置Action範圍國際化資源文件

(1).咱們也能夠爲某個action單獨制定資源文件,方法以下:在Action類所在的路徑,放置 ActionClassName_language_country.properties資源文件,ActionClassName爲Action類的 簡單名稱當查找指定key的消息時,系統會先從ActionClassName_language_country.properties資源文件查找, 若是沒有找到對應的key,而後沿着當前包往上查找基本名爲package的資源文件,一直找到最頂層包,乳溝尚未找到對應的key,最後會從常量 struts.custom.i18n.resources指定的資源文件中查找

(2).JSP中直接訪問某個資源文件

struts2爲咱們提供了 標籤,使用 標籤咱們能夠在類路徑下直接從某個資源文件中獲取國際化數據,而無需任何配置:

itcast爲類路徑下資源文件的基本名

若是要訪問的資源文件在類路徑的某個包下,能夠這樣訪問:

<s:i18nname="cn/itcast/action/package">

小張

上面訪問cn.itcast.action包下基本名爲package的資源文件

19.配置包範圍的國際化資源文件

(1).在一個大型應用中,整個應用有大量的內容須要實現國際化,若是咱們把國際化的內容都放置在全局資源屬性文件中,顯然會致使資源文件變得過於龐大、臃腫,不便於維護,這個時候咱們能夠針對不一樣模塊,使用包範圍來組織國際化文件

方法以下:在java的包下放置package_language_country.properties資源文件,package爲固定寫法,處 於該包及子包下的action均可以訪問該資源,當查找指定key的消息時,系統會先從package資源文件中查找,當找不到對應的key時,纔會從常 量struts.custom.i18n.resources指定的資源文件中尋找.

20.配置國際化全局資源文件、輸出國際化信息

(1).準備資源文件,資源文件的命名格式以下:

baseName_language_country.properties

baseName_language.properties

baseName.properties

其中baseName是資源文件的基本名,咱們能夠自定義,可是language和country必須是java支持的語言和國家。如:

中國大陸:baseName_zh_CN.properties

美國:baseName_en_US.properties

(2).如今爲應用添加兩個資源文件:

第一個存放中文:itcast_zh_CN.properties

內容爲:welcom=歡迎來到傳智播客

第二個存放英語(美國):itcast_en_US.properties

內容爲:welcome=welcom to itcast

(3).對於中文的屬性文件,咱們編寫好後,應該使用JDK提供的native2ascii命令把文件轉換爲unicode編碼的文件,命令的使用方式以下:

native2ascii 源文件.properties 目標文件.properties,在MyEclipse6.6版本以及後面的版本會自動轉換.

(4).struts2有:全局範圍,包範圍,action範圍的資源文件

(5).配置全局資源與輸出國際化信息:

當準備號資源文件以後,咱們能夠在struts.xml中經過:struts.custom.i18n.resources常量把資源文件定義爲全局資源文件,以下:

<constantname="struts.custom.i18n.resources" vlaue="itcast"/>

itcast爲資源文件的基本名

後面咱們就能夠在頁面或在action中訪問國際化信息:

在JSP頁面中使用 標籤輸出國際化信息:

<s:textname="user"/>,name爲資源文件中的key

在Action類中,能夠繼承ActionSupport,使用getText()方法獲得國際化信息,該該方法的第一個參數用於指定資源文件中的key,

在表單標籤中,經過key屬性指定資源文件中的key,如:

<s:textfieldname="realname" key="user"/>

21.請求參數接受

(1).struts1中是使用ActionForm接受用戶的請求參數

(2).採用基本類型接受請求參數(get/post):

在Action類中定義與請求參數同名的屬性,struts2便能自動接受請求參數並賦予給同名屬性:請求路徑:http://localhost:8080/test/view.action?id=78

public classProductAction{

private Integerid;

public voidsetId(Integer id){//struts2經過反射技術調用與請求參數同名的屬性的setter方法獲取請求參數值

this.id=id;

}

public IntegergetId(){return id;}

}

(3).採用複合類型接受請求參數

請求路徑:http://localhost:8080/test/view.action?product_id=78

public class ProductAction{

private Product product;

public void setProduct(Product product){htis.product=product;}

public Product getProduct(){returnproduct;}

}

struts2首先經過反射技術調用Product的默認構造器建立product對象,而後再經過反射技術調用product中與請求參數同名的屬性的setter方法來獲取請求參數值

(4).關於struts2.1.6版本中存在一個Bug,及接受到的中文請求參數爲亂碼(以post方式提交),緣由是struts2.1.6在 獲取並使用了請求參數後才調用HttpServletRequest的setCharacterEncoding()方法進行編碼設置,致使應用使用的就 是亂碼請求參數,這個Bug在struts2.1.8中已經解決,若是你使用的是struts2.1.6,要解決這個問題,你能夠這樣作:新建一個 Filter,把這個Filter放置在Struts2的Filter以前,而後再doFilter()方法中添加如下代碼:

public void doFilter(..){

HttpServletRequest req=(HttpServletRequest)request;

req.setCharacterEncoding("UTF-8");

filterchain.doFilter(request,response);

}

22.全局類型轉換器

自定義全局類型轉換器:將上面的類型轉換器註冊爲全局類型轉換器:在WEB-INF/classes下放置xword-conversion.properties文件,在properties文件中的內容爲:待轉換的類型=類型轉換器的全類名

對於本例而言,xwork-conversion.properties文件中的內容爲:

java.util.Date=cn.itcast.conversion.DateConverter

23.輸出帶有佔位符的國際化信息

(1).資源文件中的內容以下:

welcom={0}歡迎來到傳智播客{1}

在jsp頁面中輸出帶佔位符的國際化信息

<s:propertyvalue="realname"/>

學習

在Action類中獲取帶佔位符的國際化信息,能夠使用getText(String key,String[] args)或getText(StringaTextName,List args)方法.

(2).佔位符就當是一個變量參數,能夠傳遞給定的參數值.

24.爲Action屬性注入值

struts2爲Action中的屬性提供了依賴注入功能,在struts2的配置文件中,咱們能夠很方便的爲Action中的屬性注入值,注意:屬性必須提供setter方法,

public class HelloWorldAction{

private String savePah;

public String getSavePath(){

            return savePath;

      }

public void setSavePath(String savePath){

      this.savePath=savePath;

      }

}

<paramname="savePath">/images

<resultname="success">/WEB-INF/page/hello.jsp

上面經過節點爲action的savePath屬性注入"/images";Action的變量的值,不能寫死,常常變換,須要經過配置來設置參數

25.爲應用指定多個配置文件

(1).在大部分應用中,隨着應用規模的增長,系統中的Action的數量也會大量增長,致使struts.xml配置文件變得很是臃腫,爲了不 struts.xml文件過於龐大、臃腫,提升struts.xml文件的可讀性,咱們能夠講一個struts.xml配置文件分解成多個配置文件,而後 再struts.xml文件中包含其餘配置文件,下面的struts.xml經過 元素指定多個配置文件:

<includefile="struts-user.xml"/>

<includefile="struts-order.xml"/>

經過這種方式,咱們就能夠將struts2的Action按模塊添加在多個配置文件中

26.文件上傳

第一步:在WEB-INF/lib下加入commons-fileupload-1.2.1.jar、commons-io-1.3.2.jar, 這兩個文件能夠從http://commons.apache.org下載,在struts2.1之前的版本須要添加,之後的版本就不須要添加

第二步:把form表的enctype設置爲:"multipart/form.data",以下:

這個屬性的name必需要和類中File名稱同樣

第三步:在Action類中添加如下屬性

public class HelloWorldAction{

private File uploadImage;//獲得上傳文件;

private String uploadImageContentType;//獲得文件的類型

private String uploadImageFileName;//獲得文件的名稱

//這裏省略了屬性的get/set方法(可是要注意get/set方法是必須的)

public String upload() throws Exception{

String realpath =ServletActionContext.getServletContext().getRealPath("/images");

File file=new File(realpath);

if(file.getParentFile().exists())file.getParentFile().mkdirs();//目錄是否存在,不存在就建立

FileUtils.copyFile(uploadImage,newFile(file,uploadImageFileName));

return "success";

}

}

(1).若是文件不保存,struts2會把文件保存到本身的目錄中,可是當這個Action執行完後,該文件就會被刪除,因此咱們要將上傳的文件保存到硬盤上

(2).最好還要判斷如下,文件uploadImage是否爲空

(3).若是上傳大的文件,web都會失敗,像一些門戶網站上傳視頻,都是經過一個插件,能夠把這個插件當作一個程序,只是這個程序是經過Socket變成的,針對一個端口進行傳輸數據

27.指定struts2處理的請求後綴

(1).前面咱們都是默認使用.action後綴訪問Action,其實默認後綴是能夠經過常量"struts.action.extension"進行修改的,例如:咱們能夠配置struts2只處理以.do爲後綴的請求路徑

<constantname="struts.action.extendsion" value="do"/>

若是用戶須要制定多個請求後綴,則多個後綴之間以英文逗號","隔開,如:

<constantname="struts.action.extendsion" value="do,go"/>

(2).常量能夠在struts.xml或struts.properties中配置,建議在struts.xml中配置,兩種配置方式以下:

在struts.xml文件中配置常量:

<constantname="struts.action.extendsion" value="do"/>

在struts.properties中配置常量:

struts.action.extension=do

由於常量能夠在下面多個配置文件中進行定義,因此咱們須要瞭解struts2加載常量的搜索順序:

struts-default.xml

struts-plugin.xml

struts.xml

struts.properties

web.xml

若是在多個文件中配置了同一個常量,則後一個文件中配置的常量值會覆蓋前面文件中配置的常量值

(3).

第一:默認編碼集,做用於HttpServletRequest的setCharacterEncoding方法和freemarker、velocity的輸出:

<constantname="struts.i18n.encoding" value="UTF-8"/>

第二:該屬性指定須要struts2處理的請求後綴,該屬性的默認值是action,即全部匹配*.action的請求都由struts2處理,若是用戶須要指定多個請求後綴,則多個後綴之間以英文逗號(,)隔開

第三:設置瀏覽器是否緩存靜態內容默認值爲true(生產環境下使用)開發階段最好關閉,否則看不到修改後的數據

<constantname="struts.serve.static.browserCache" value="false"/>

第四:當struts的配置文件修改後系統是否自動從新加載該文件默認值爲false(生產環境下使用),開發階段最好打開

<constantname="struts.configuration.xml.reload" value="true"/>

第五:開發模式下使用,這樣能夠打印出更詳細的錯誤信息

第六:默認的視圖主題

<constantname="struts.ui.theme" value="simple"/>

第七:與spring集成時,指定由spring負責action對象的建立

<constantname="struts.objectFactory" value="spring"/>

第七:該屬性設置struts2是否支持動態方法調用,該屬性的默認值是true,若是須要關閉動態方法調用,則可設置該屬性爲false

<constantname="struts.enable.DynamicMethodInvocation"value="false"/>

第八:上傳全部文件的總大小限制

constantname="struts.mulitipart.maxSize" value="10701096"/>

28.自定義攔截器

(1).若是用戶登陸後能夠訪問action中的全部方法,若是用戶沒有登陸不容許訪問action中的方法,而且提示"你沒有權限執行該操做"

(2).

<interceptorname="permission"class="cn.itcast.interceptor.PermissionInterceptor"/>

<actionname="list_*" class="cn.itcast.action.HelloWorldAction"method="{1}">

<interceptor-refname="permission"/>

若是爲某一個Action定義一個攔截器,struts2中對Action的默認的不少攔截器都失去功能,因此要想作到一箭雙鵰,須要定義一個攔截器棧:

<interceptorname="permission"class="cn.itcast.interceptor.PermissionInterceptor"/>

<interceptor-stackname="permissionStack">

<interceptor-refname="defaultStack"/>

<interceptor-refname="permission"/>

由於struts2中如文件上傳,數據驗證,封裝請求參數到action等功能都是由系統默認的defaultStack中的攔截器實現的,因此我 們定義的攔截器須要引用系統默認的defaultStack,這樣應用才能夠使用struts2框架提供的衆多功能,若是但願包下的全部action都使 用自定義的攔截器,能夠經過<default-interceptor-refname="permissionStack"/>把攔截器定 義爲默認攔截器,注意:每一個包只能指定一個默認攔截器,另外,一旦咱們爲該包中的某個action顯示指定了某個攔截器,則默認攔截器不會起做用.

(3).系統默認的攔截器能夠到struts-default.xml中查看,不少功能.系統攔截器放在最前面,自定義的攔截器放在後面.

29.自定義類型轉換器

(1).struts2中提供了兩種類型轉換器:局部類型轉換器(只對某一個action起做用),全局類型轉換器(全部的action起做用)

(2).類型轉換器必須繼承DefaultTypeConverter最好用xwork2.jar中的,重寫converValue(Map<String,Object>context,Objectvalue,Class toType){

returnsuper.convertValue(context,value,toType);

}

其中第一個參數和ognl表達式,第二個參數是須要轉換類型的內容(是String數組,由於可能有多個值),第三個參數是須要轉換成什麼類型,要實現雙向轉換

(3).將上面的類型轉換器註冊爲局部類型轉換器:

在Action類所在的包下放置ActionClassName-conversion.properties文 件,ActionClassName是Action的類名,後面的-conversion.properties是固定寫法,對於本例而言,文件的名稱應 爲HelloWorldAction-conversion.properties.在properties文件中的內容爲:

須要轉換的屬性名稱=類型轉換器的全類名

對於本例而言,HelloWorldAction-conversion.properties文件中的內容爲:

createtime=cn.itcast.conversion.DateConverter

4、 Spring

  1. @Autowired註解與自動裝配

@Autowired

private PersonDaopersonDao;

拿PersonDao與<bean id=""..../>中的id值進行比較,相同就找到了,即進行類型註解,固然也能夠過@Qualifier註解進行名稱進行註解.

自動裝配:

對於自動裝配,你們瞭解一下就能夠了,實在不推薦你們使用,例子:

autowire屬性取值以下:

byType:按類型裝配,能夠根據屬性的類型,在容器中尋找根該類型匹配的bean,若是發現多個,那麼將會拋出異常,若是沒有找到,即屬性值爲null

byName:按名稱裝配,能夠根據屬性的名稱,在容器中尋找跟該屬性名相同的bean,若是沒有找到,即屬性值爲null

construtor與byType的方式相似,不一樣之處在於它應用於構造器參數,若是在容器中沒有找到與構造器參數類型一致的bean,那麼將會拋出異常.

autodetect:經過bean類的自省機制,來決定是使用constructor仍是byType方式進行自動裝配,若是發現默認的構造器,那麼將使用byType方式.

  1. @Resource註解完成屬性裝配

(1).前面講到了使用構造器注入,屬性的setter方法注入,這裏還能夠使用註解的方式對Field進行注入

(2).注入依賴對象能夠採用手工裝配或自動裝配,在實際應用中建議使用手工裝配,由於自動轉配會產生未知狀況,開發人員沒法預見最終的裝配結果

(3).手工裝配依賴對象,在這種方式中又有兩種編程方式

方式一:在XML配置文件中,經過在Bean節點下配置,如:

構造器注入

屬性的setter方法注入

在XML中注入屬性,會給XML文件變得很臃腫.特別是對集合類型進行注入時,變得很臃腫.

方式二:

在java代碼中使用@Autowire或@Resoruce註解方式進行裝配,但咱們須要在XML配置文件中配置如下信息:

<beansxmlns="http://www.springframe.....

....

....

這些配置項隱式註冊了多個對註釋進行解析處理的處理 器:AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor,RequireAnnotationBeanPostProcessor, 每一個註解都有一個註解處理器,註解自己不幹活,是相對應的註解處理器在幹活

注:@Resource註解在spring安裝目錄的lib\j2ee\common-annotations.jar

(4).在java代碼中使用@Autowired或@Resource註解方式進行裝配,這兩個註解的區別是:

@Autowired默認按類型裝配,@Resource默認按名稱裝配,當找不到與名稱匹配的bean纔會按類型裝配.

@Autowired

private PersonDaopersonDao;//用於字段上

@Autowired

public voidsetOrderDao(OrderDao orderDao){//用於setter方法上

this.orderDao=orerDao;

}

@Autowired註解是按類型裝配依賴對象,默認狀況下,它要求依賴對象必須存在,若是容許null值,能夠設置它required的屬性爲false,若是咱們想使用按名稱裝配,能夠結合@Qualifier註解一塊兒使用,以下:

@Autowired@Qualifier("personDaoBean")

private PersonDaopersonDao;

@Resource註解和@Autowired同樣,也能夠標註在字段或屬性的setter方法上,但他默認按名稱裝配,名稱能夠經過 @Resource的name屬性執行,若是沒有指定name屬性,當註解標註在字段上,即默認取字段的名稱做爲bean名稱尋找依賴對象,當註解標註在 屬性的setter方法上,即默認取屬性名做爲bean名稱尋找依賴對象

@Resource(name="personDaoBean")

private PersonDaopersonDao;//用於字段上

注意:若是沒有指定name屬性,而且按照默認的名稱仍然找不到依賴對象時,@Resoruce註解會回退到按類型裝配,但一旦指定了name屬 性,就只能按名稱裝配了.拿personDao與<bean id=" ".../>中的id是否相同,相同就找到,屬性的setter方法也不用寫,既方便,又優雅.

同時@Resource是j2ee提供的註解(建議使用),@Autowired是spring框架提供的.

  1. Spring的三種實例化Bean的方式

(1).三種實例化bean的方式:

第一種:<bean id="orderService"class="cn.itcast.OrderServiceBean/>

第二種:使用靜態工廠方法實例化:

public class OrderFactory{

public static OrderServiceBeancreateOrder(){

return new OrderServiceBean();

}

}

第三種:使用實例工廠方法實例化:

<beanid="personServiceFactory" class="cn.itcast.service.OrderFactory"/>

public class OrderFactory{

public OrderServiceBean createOrder(){

return new OrderServiceBean();

}

}

  1. Spring管理的Bean的生命週期

(1).Bean實例化是在Spring容器實例化時進行的,可是這是Singleton做用域中,實例化的時機是能夠更改的,lazy- init="true"延遲初始化,即更改成調用getBean()方法時進行初始化.同時也能夠在配置文件中設置全部的bean延遲初始化,其實這個標 籤是不建議使用的.

(2).當把做用域改爲Prototype時,Bean實例化是在調用getBean()方法進行的

(3).能夠指定一個初始化方法:init-method="";即在bean實例化後執行的初始化方法.如數據庫的鏈接.容器經過反射技術調用的,同時還須要進行資源的釋放.destory-method="";即在bean被銷燬時執行的方法.

(4).關閉Spring容器:ctx.close()方法,bean此時被銷燬了

5.Spring自動掃描和管理bean

經過在classpath自動掃描方式把組件歸入spring容器中管理,前面的例子咱們都是使用XML的bean定義來配置組件,在一個稍大的項 目中,一般會有上百個組件,若是這些組件採用xml的bean定義來配置,顯然會增長配置文件的體積,查找及維護起來也不太方便,spring2.5爲我 們引入了組件自動掃描機制,它能夠在類路徑底下尋找標註了@Componet、@Service、@Controller、@Reponsitory註解 的類,並把這些類歸入進spring容器中管理,它的做用和在XML文件中使用bean節點配置組件是同樣的,要使用自動掃描機制,咱們須要打開如下配置 信息:

<beansxmln="http://www.springframework.org/schema/beans"

....

....

其中base-package爲須要掃描的包(含子包)

@Service用於標註業務層組件、@Controller用於標註控制層組件(如struts中的action)、@Repository用於 標註數據訪問組件,即Dao組件,而@Component泛指組件,當組件很差歸類的時候,咱們能夠使用這個註解進行標註.同時也能夠經過註解 @Scope("prototype")修改bean的做用域.@Service("personService")中的名稱必須和bean的名稱相同, 只是開頭字母變成小寫了.固然這是默認設置,能夠修改的.

能夠使用註解的方式指定初始化方法,在初始化方法init()上添加註解@PostConstruct,一樣能夠指定銷燬方法destroy(),註解爲:@PreDestroy

這種掃描方式是很方便的,不少人都採用

即前面所說的功能都使用註解進行操做

6. SSH整合開發

hibernate核心安裝包下的:

hibernate3.jar

lib\required*.jar

lib\optional\ehcache-1.2.3.jar

hibernate註解安裝包下的

lib\test\slf4j-log4j12.jar

Spring安裝包下的

dist\spring.jar

dist\modules\spring-webmvc-struts.jar

lib\jakarta-commons\commons-logging.jar、commons-dbcp.jar、commons-pool.jar

lib\aspectj\aspectjweaver.jar、aspectjrt.jar

lib\cglib\cglib-nodep-2.1.3.jar

lib\j2ee\common-annotations.jar

lib\log4j-1.2.14.jar

Struts:下載struts-1.3.8-lib.zip,須要使用到解壓目錄下的全部jar,建議把jstl-1.0.2.jar和 standard-1.0.2.jar更換爲1.1版本,Spring中已經存在一個antlr-2.7.6.jar,因此把struts中的 antlr-2.7.2.jar刪除,避免jar衝突

數據庫驅動jar

首先整合struts和hibernate而後再整合spring

7.編碼解析@Resource註解的實現原理

(1).新建一個註解

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.Field,ElementType.METHOD})

public @interface ItcastResource{

String name() default "";

}

固然還要編寫一個註解處理器.

private voidannotationInject(){

首先循環全部的bean對象,判斷其是否使用了註解

若是使用了註解,就進行屬性注入.

}

8.編碼解析Spring依賴注入的原理

(1).基本類型對象注入:

構造器注入

//屬性setter方法注入

(2).注入其餘bean:

方式一:

ref是指被注入的對象personDao

方式二:(使用內部bean,但該bean不能被其餘bean使用)

<beanclass="cn.itcast.service.OrderDaoBean"/>

(3).依賴注入的內部原理

9.編碼解析Spring裝配基本屬性原理

也能夠對基本類型進行注入,類型轉換.

10.編碼剖析Spring管理bean的原理

使用dom4j讀取spring配置文件,使用反射技術便可

11.搭建和配置Spring與JDBC整合的環境

(1).配置數據源:

apache的數據源:BasicDataSource

<propertyname="driverClassName" value="org.gjt.mm.mysql.Driver"/>

鏈接池啓動時的初始值

鏈接池的最大值

最大空閒值

最小空閒值

配置事務:

採用註解的方式:

<ts:annotation-driventransaction-manager="txManage"/>

12.搭建與測試spring的開發環境

(1).dist\spring.jar;

lib\jakarta-commons\commons-logging.jar

以上這兩個包是必須的

lib\aspectj\aspectjweaver.jar和aspectjrt.jar

lib\cglib\cglib-nodep-2.1.3.jar

以上這兩個包是用於切面編程(AOP)

lib\j2ee\common-annotations.jar

以上的這個包是JSR-250中的註解

(2).Spring項目既能夠在j2se中也能夠在j2ee中

(3).spring的配置文件模板能夠從spring的參考手冊或spring的例子中獲得,配置文件的取名能夠任意,文件能夠存放在任何目錄下,但考慮到通用性,通常放在類路徑下

(4).實例化spring容器經常使用方式:

第一種方式:在類路徑下尋找配置文件來實例化容器

ApplicationContextctx=new ClassPathXmlApplicationContext(new String[]{"beans.xml"});

第二種方式:在文件系統路徑下尋找配置文件來實例化容器

ApplicationContextctx=new FileSystemXmlApplicationContext(newString[]{"d:\beans.xml"});//將路徑寫死了,通用性很差,不建議使用.

spring的配置文件能夠指定多個,能夠經過String數組傳入

(5).IOC:控制反轉:

public class PersonServiceBean{

private PersonDao personDao = newPersonDaoBean();

public void save(Person person){

personDao.save(person);

}

}

PersonDaoBean是在應用內部建立及維護的,所謂控制反轉就是應用自己不負責依賴對象的建立及維護,依賴對象的建立及維護是由外部容器負責的,這樣控制權就由應用轉移到外部容器,控制權的轉移就是所謂反轉.

(6).創建一個業務bean爲PersonServiceBean,放在cn.itcast.service.impl包中.面向接口編程,進行 解耦,怎麼將業務bean交給spring管理,須要在beans.xml配置文件中: ,其中id,name都是bean的名稱,可是id不能使用特殊字符,id自己就屬於 XML屬性的,如:"/sfs/"就會出錯,可是name不會出錯,class屬性是bean類的路徑,須要操縱bean的時候,只需到spring容器 中取出bean進行操做,而不須要實例化一個bean了:

ApplicationContext ctx=newClassPathXmlApplicationContext(new String[]{"beans.xml"});

PersonServiceBeanpersonService=(PersonServiceBean)ctx.getBean("personService");

personService.save();

(7).當在配置文件中沒有標籤的提示信息,須要手動添加schema文件,方法如 下:windows->preferences->myeclipse->filesand editors->xml->xmlcatalog,點擊添加,在出現的窗口中的Key Type中選擇URL,在location中選"File System",而後在spring解壓目錄的dist/resources目錄中選擇spring-beans-2.5.xsd,回到設置窗口的時候不 要急着關閉窗口,應該把窗口的Key Type改成Schema location,Key改成http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

13.配置Spring管理的bean的做用域

(1).Singleton:默認狀況下,bean是單例模式的,在每一個springIoc容器中一個bean定義只有一個對象實例,默認狀況下會 在容器啓動時初始化bean,可是咱們能夠指定Bean節點的lazy-init="true"來延遲初始化bean,這時候,只有第一次獲取bean會 才初始化bean,如:

若是想對全部bean都應用延遲初始化,能夠在根節點beans設置default-lazy-init="true",以下:

Prototype:每次從容器獲取bean都是新的對象

Request:在request的域中

Session:在Session的域中

Global Session:在全局的Session的域中

14.全面闡釋Spring及其各項功能

(1).Spring是一個開源的控制反轉(Inversion of control,IoC)和麪向切面(AOP)的容器框架,它的主要目的是簡化企業開發

(2).IOC:控制反轉:

public class PersonServiceBean{

private PersonDao personDao = newPersonDaoBean();

public void save(Person person){

personDao.save(person);

}

}

PersonDaoBean是在應用內部建立及維護的,所謂控制反轉就是應用自己不負責依賴對象的建立及維護,依賴對象的建立及維護是由外部容器負 責的,這樣控制權就由應用轉移到外部容器,控制權的轉移就是所謂反轉.PersonServiceBean是業務邏輯層類,PersonDaoBean是 Dao層類,在業務邏輯層類中控制和建立PersonDaoBean,這就是應用自己建立和維護了,可是有了spring容器 後,PersonDaoBean的建立和維護是在容器中進行的,不須要PersonServiceBean進行管理了,控制權進行的反轉

(3).依賴注入:當咱們把依賴對象交給外部容器負責建立,那麼PersonServiceBean類能夠改爲以下:

public class PersonServiceBean{

private PersonDao personDao;

//經過構造器參數,讓容器把建立好的依賴對象注入進PersonServiceBean,固然也能夠使用setter方法進行注入

public PersonServiceBean(PersonDaopersonDao){

this.personDao=personDao;

}

public void save(Person person){

personDao.save(person);

}

}

所謂依賴注入就是指:在運行期,由外部容器動態的將依賴對象注入到組件中.

(4).爲什麼要使用spring:

第一:下降組件之間的耦合度,實現軟件各層之間的解耦:

Controller->Service->Dao

第二:能夠使用容器提供的衆多服務,如:事務管理服務,消息服務等,當咱們使用容器管理事務時,開發人員就再也不須要手工控制事務,也不須要處理複雜的事務傳播

第三:容器提供單例模式支持,開發人員不在須要本身編寫實現代碼

第四:容器提供了AOP技術,利用它很容易實現如權限攔截、運行期監控等功能

第五:容器提供的衆多輔助類,使用這些類可以加快應用的開發,如:JdbcTemplate,HibernateTemplate

第六:Spring對於主流的應用框架提供了集成技術,如集成Hibernate、JPA、Struts等,這樣更便於應用的開發.

(5).輕量級和重量級概念的劃分,其實劃分一個應用是否屬於輕量級仍是重量級,主要看他使用了多少服務,使用的服務越多,容器要爲普通的java 對象的工做就越多,必然會影響到應用的發佈時間或者是運行性能,對於spring容器,它提供了不少服務,可是這些服務並非默認爲應用打開的,應用須要 某種服務,還須要指明使用該服務,若是應用使用的服務不多,如:只是用了spring的核心服務,那麼咱們就能夠認爲此時應用屬於輕量級的,若是應用使用 了spring提供的大部分服務,這時應用就屬於重量級,目前EJB容器就由於他默認爲應用提供了EJB規範中全部的功能,因此他屬於重量級

15.使用CGLIB實現AOP功能與AOP概念詳解

(1).使用cglib架包,構建代理,不須要被代理的對象須要實現接口

public class CGlibProxyFactory implementsMethodInterceptor{

private Object targetObject;

public Object createProxyIntance(ObjecttargetObject){

this.targetObject=targetObject;

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(this.targetObject.getClass());

enhancer.setCallback(this);

return enhancer.create();

}

public Object intercep(Object proxy,Method method,Object[]args,MethodProxy methodProxy)throws Throwable{

returnmethodProxy.invoke(this.targetObject,args);

}

}

CGLIB能夠生成目標類的子類,並重寫父類非final修飾符的方法

16.使用JDK中的Proxy技術實現AOP功能

(1).使用在權限攔截上.

(2).被代理對象必須實現接口

public class JDKProxyFactory implementsInvocationHandler{

private Object targetObject;

public Object createProxyIntance(ObjecttargetObject){

returnProxy.newProxyInstance(this.targetObject.getClass().getClassLoader(),this.targetObject.getClass().getInterfaces(),this);

}

public Object invoke(Object proxy,Methodmethod,Object[]args) throws Throwable{//環繞通知

PersonServiceBean bean=(PersonServiceBean)this.targetObject;

Object result=null;

if(bean.getUser()!=null){

//....advice(),調用方法前處理,叫作前置通知

try{

result=method.invoke(targetObject,args);

//....afteradvice();調用方法後處理,叫作後置通知

}catch(RuntimeException e){

//....exceptionadvice();調用方法出現例外後處理,叫作例外通知

}finally{

//....finallyadvice();調用方法最終都會處理,叫作最終通知

}

}

return result;

}

}

整個invoke方法叫作環繞通知.

(3).AOP中的概念:

Aspect(切面):指橫切性關注點的抽象即爲切面,它與類類似,只是二者的關注點不同,類是對物體特徵的抽象,而切面是橫切性關注點的抽象。

JoinPoint(鏈接點):所謂鏈接點是指那些被攔截到的點,在spring中,這些點指的是方法,由於spring只支持方法類型的鏈接點,實際上joinpoint還能夠是field或類構造器

Pointcut:切入點:所謂切入點是指咱們要對那些joinpoint進行攔截的定義

Advice(通知):所謂通知是指攔截到joinpoint以後所要作的事情就是通知,通知分爲前置通知,後置通知,異常通知,最終通知,環繞通知

Target(目標對象):代理的目標對象

Weave(織入):指將aspect應用到target對象並致使proxy對象建立的過程稱之爲織入

Introduction(引入):在不修改類代碼的前提下,Introduction能夠在運行期爲類動態的添加一些方法或Field

17.使用Spring的註解方式實現AOP

(1).要進行AOP編程,首先咱們要在Spring的配置文件中引入AOP命名空間:

<beansxmlns="http://www.springframework.org/schema/beans"

Spring提供了兩種切面使用方式,實際工做中咱們能夠選用其中一種:一種是基於XML配置方式進行AOP開發,另一種是基於註解方式進行AOP開發

(2).基於註解方式聲明切面:首先啓動對@AspectJ註解的支持:

定義一個切面類(MyInterceptor):

@Aspect

public class MyInterceptor{

@Pointcut("execution(cn.itcast.service...*(..))

//定義切入點,通配符:指的是任何返回類型,..是指子包下也進行攔截,:指的是攔截全部類,*:指定的是全部方法,..是指任意參數

private void anyMethod(){}//聲明一個切入點

@Before("anyMethod()")//定義一個前置通知,名稱爲切入點名稱

public void doAccessCheck(){

System.out.println("前置通知");

}

@AfterReturning("anyMethod()")//後置通知

public void doAfterReturning(){

System.out.println("後置通知");

}

@After("anyMethod()")//最終通知

public void doAfter(){

System.out.println("最終通知");

}

@AfterThrowing("anyMethod()");//例外通知

public void doAfterThrowing(){

System.out.println("例外通知");

}

@Around("anyMethod()")//環繞通知

public ObjectdoBasicProfiling(ProceedingJoinPoint pjp)throws Throwable{

System.out.println("進入方法");

if(){//判斷用戶是否有權限,有權限就執行該方法.

Object result = pjp.proceed();

System.out.println("退出方法");

}else{

}

return result;

}

}

因此當出現例外通知時,後置通知是不執行的,即它們二者確定有一個不執行,一個執行.

須要將切面類交給spring管理:基於XML配置管理或者自動掃描管理

(3).想獲得參數:

@Before(anyMethod() &&args(userName)")//添加參數,只會攔截到對應的方法,即一個參數的方法.

public void doAccessCheck(String name){

System.out.println("前置通知");

}

(4).想獲得返回結果:

@AfterReturning("anyMethod()",returning="result")//後置通知

public void doAfterReturning(String result){

System.out.println("後置通知");

System.out.println(result);//打印返回結果

}

(5).獲得異常(例外):

@AfterThrowing("anyMethod()",throwing="e");//例外通知

public void doAfterThrowing(Exception e){

System.out.println("例外通知");

System.out.println(e);//打印例外

}

18.使用Spring配置文件實現AOP

(1).使用配置文件實現AOP,切面類只是個普通的類,其內部沒有任何註解

public class MyInteceptor{

public void doAccessCheck(){

System.out.println("前置通知");

}

public void doAfterReturning(){

System.out.println("後置通知");

}

public void doAfter(){

System.out.println("最終通知");

}

public void doAfterThrowing(){

System.out.println("例外通知");

}

public ObjectdoBasicProfiling(ProceedingJoinPoint pjp)throws Throwable{

System.out.println("進入方法");

Object result=pjp.proceed();

System.out.println("退出方法");

return result;

}

}

(2).基於XML配置方式聲明切面

<aop:beforepointcut-ref="mycut" method="doAccessCheck"/>

<aop:after-returningpointcut-ref="mycut" method="doReturnCheck"/>

<aop:after-throwingpointcut-ref="mycut" method="doExceptionAction"/>

<aop:afterpointcut-ref="mycut" method="doReleaseAction"/>

<aop:aroundpointcut-ref="mycut" method="doBasicProfiling"/>

(3).對於表達式expression的細節:

返回值類型爲String:execution(java.lang.Stringcn.itcast.service...(..))

第一個參數爲String:execution(java.lang.Stringcn.itcast.service...(java.lang.String..))

返回值類型爲非void:execution(!void cn.itcast.service...(..))

19.使用Spring配置文件實現事務管理

(1).

<aop:pointcutid="transactionPointcut" expression="execution(cn.itcast.service..*(..))"/>對指定的方法進行攔截

<aop:advisoradvice-ref="txAdvice"pointcut-ref="transactionPointcut"/>

<tx:adviceid="txAdvice" transaction-manager="txManager">

<tx:methodname="*"/>

20.使用Spring註解方式管理事務與傳播行爲詳解

(1).只有當遇到RuntimeException時,事務進行回滾.Spring開啓的事務管理,當遇到運行期例外(unchecked),而(checked異常)是不進行事務的回滾的.

(2).固然也可修改這種狀況.把unckecked異常改爲不會進行回滾了:@Transactional(noRollbackFor=RuntimeException.class),

(3).@Transactional(propagation=Propagation.NOT_SUPPORTED);關閉事務,不開啓事務的.spring容器默認是打開事務的.固然還有其餘一些值:(事務的傳播行爲)

REQUIRED:業務方法須要在一個事務中運行,若是方法運行時,已經處在一個事務中,那麼加入到該事務,不然爲本身建立一個新的事務(容器的默認值)

NOT_SUPPORTED:聲明方法不須要事務,若是方法沒有關聯到一個事務,容器不會爲他開啓事務,若是方法再一個事務中被調用,該事務會被掛起,在方法調用結束後,原先的事務便會恢復執行

REQUIRESNEW:屬性聲明無論是否存在事務,業務方法總會爲本身發起一個新的事務,若是方法已經運行在一個事務中,則原有事務會被掛起,新的事務會被建立,直到方法執行結束,新事務纔算結束,原先的事務纔會恢復執行

MANDATORY:該屬性指定業務方法只能在一個已經存在的事務中執行,業務方法不能發起本身的事務,若是業務方法再沒有事務的環境下調用,容器就會拋出異常

SUPPORTS:這一事務屬性聲明,若是業務方法再某個事務範圍內被調用,則方法成爲該事務的一部分,若是業務方法再事務範圍外被調用,則方法再沒有事務的環境下執行

Never:指定業務方法絕對不能在事務範圍內執行,若是業務方法再某個事務中執行,容器會拋出異常,只有業務方法沒有關聯到任何事務,才能正常執行.

NESTED:若是一個活動的事務存在,則運行在一個嵌套的事務中,若是沒有活動事務,則按REQUIRED屬性執行,它使用了一個單獨的事務,這 個事務擁有多個能夠回滾的保存點,內部事務的回滾不會對外部事務形成影響,它只對DataSourceTransactionManager事務管理器起 效.Savepoint savepoint=conn.setSavepoint();conn.rollback(savepoint);

(4).readOnly值爲事務不能修改了.timeout是事務的超時時間,isolation數據庫中的隔離級別.

(5).數據庫系統提供了四種事務隔離級別供用戶選擇,不一樣的隔離級別採用不一樣的鎖類型來實現,在四種隔離級別中,Serializable的隔離 級別最高,Read Uncommited的隔離級別最低,大多數據庫默認的隔離級別爲Read Commited,如SQLServer,固然也有少部分數據庫默認的隔離級別爲Repeatable Read,如MySql

Read Uncommited:讀未提交數據(會出現髒讀,不可重複讀和幻讀)

Read Commited:讀已提交數據(會出現不可重複讀和幻讀)

Repeatable Read:可重複讀(會出現幻讀)

Serializable:串行化

髒讀:一個事務讀取到另外一個事務未提交的更新數據

不可重複讀:在同一事務中,屢次讀取同一數據返回的結果有所不一樣,換句話說就是,後續讀取能夠讀到另外一事務已經提交的更新數據,相反,「可重複讀」在同一事務中屢次讀取數據時,可以保證所讀數據同樣,也就是,後續讀取不能讀到另外一事務已提交的更新數據.

幻讀:一個事務讀取到另外一個事務已提交的insert數據.

5、 Hibernate

1. Criteria查詢方式

(1).Criteria查詢方式(條件查詢):

Criteriac=s.createCriteria(User.class);

c.add(Restrictions.eq("name",name));//添加查詢條件,User中的name屬性的值是否等於"name"

List list=c.list();

Useru=(User)c.uniqueResult();

2. hibernate的二級緩存配置與分析

(1).二級緩存:SessionFactory級共享:

實現爲可插拔,經過修改cache.provider_class參數來改變;hibernate內置了對 EhCache.OSCache,TreeCaceh,SwarmCache的支持,能夠經過實現CacheProvider和Cache接口來加入 Hibernate不支持的緩存實現

在hibernate.cfg.xml中加入:

<class-cacheclass="className" usage="read-only"/>或在映射文件的class元素加入子元素:

其中usage:read-only,read-write,nonstrict-read-write,transactional

Session的save(這個方法不適合native生成方式的主 鍵),update.saveOrUpdate,list,iterator,get,load,以及Query,Criteria都會填充二級緩存,但 只有(沒有打開查詢緩存時)Session的iterator,get,load會從二級緩存中取數據(iterator可能存在N+1次查詢)

Query,Criteria(查詢緩存)因爲命中率較低,因此hibernate缺省是關閉;修改cache,use_query_cache爲 true打開對查詢的緩存,而且調用query.setCaheable(true)或criteria.setCacheable(true)

SessionFactory中提供了evictXXX()方法用來清除緩存中的內容

統計消息打開generate_statistics,用sessionFactory.getSatistics()獲取統計信息,獲取統計信息成本是很高的,消耗資源.對程序的調試是頗有幫助的,能夠看到session的初始化時間,打開多少次,關閉多少次等信息.

(2).相對user對象進行緩存:

<class-cacheclass="cn.itcast.hibernate.domain.User"usage="read-only"/>只讀方式,效率高,User類不會再改變了.可以保證併發.

(3).先到一級緩存中查找,找不到在到二級緩存中查找

3.Hibernate的攔截器和監聽器

(1).攔截器和事件

攔截器與事件都是hibernate的擴展機制,Interceptor接口是老的實現機制,如今改爲事件監聽機制,他們都是hibernate的回調接口,hibernate在save,delete,update等會回調這些查詢

(2).攔截保存的的事件:

實現SaveOrUpdateEventListener接口

public classSaveListener implements SaveOrUpdateEventListener{

public voidonSaveOrUpdate(SaveOrUpdateEvent event){

if(event.getObject()instantce of cn.itcast.hibernate.domain.User){

User user =(User)event.getObject();

System.out.println(user.getName().getFirstName());

}

}

}

配置文件中:

<eventtype="save">

<listenerclass="cn.itcast.hibernate.SaveListener"/>本身定義的監聽器,不一樣監聽器的註冊順序,輸出的結果也是不一樣的.

<listenerclass="org.hibernate.evetn.def.DefaultSaveOrUpdateEventListenter"/& gt;hibernate缺省的監聽器,本身定義的監聽器會覆蓋缺省的,因此在這裏還要把缺省的監聽器註冊一下.

當保存user時,會監聽到.

4.hibernate的內部緩存分析

(1).第一級緩存是在session中,第二緩存是在sessionFactory

(2).Useruser=(User)s.get(userClass,id);

System.out.println(user.getClass());

user=(User)s.get(userClass,id);

只有一條select語句

(3).當session關閉時,緩存也就沒有數據了.

(4).緩存的做用主要用來提升性能,能夠簡單的理解成一個Map,使用緩存涉及到三個操做:把數據放入緩存、從緩存中獲取數據、刪除緩存中的無效數據

(5).一級緩存,Session級共 享,save,update,saveOrUpdate,load,get,list,iterate,lock這些方法都會將對象放在一級緩存中,一級 緩存不能控制緩存的數量,因此要注意大批量操做數據時可能形成內存溢出,能夠用evict,clear方法清除緩存的內容.

(6).只要有sql語句,就不會去緩存中拿數據,直接到數據庫中拿數據

(7).手工的對緩存中的數據進行清除.清除一條記錄:s.evict(user);清除全部的記錄s.clear();定時的清除能夠下降內存溢出的可能性.

(8).session的生命週期很短,只在一個web請求內

5.hibernate介紹與動手入門體驗

(1).模型不匹配:Java面嚮對象語言,對象模型,其主要概念有:繼承,關聯,多態等,數據庫是關係模型,其主要概念有:表,主鍵,外鍵等

(2).解決方法:第一種:使用JDBC手工轉換,第二種使用ORM框架來解決,主流的ORM框架有Hibernate、TopLink、OJB

(3).下載hibernate,將下載目錄/hibernate3.jar和/lib下的hibernate運行時必須的包

(4).配置文件hibernate.cfg.xml和hibernate.properties,XML和properties兩種,這兩個文件的做用同樣,提供一個便可,推薦XML格式,下載目錄/etc下是示例配置文件

能夠在配置文件制定:

數據庫的URL,用戶名,密碼,JDBC驅動類,方言等,啓動時Hibernate會在CLASSPATH裏找這個配置文件.映射文件(hbm.xml,對象模型和關係模型的映射),在/eg目錄下有完整的hibernate示例

(5).首先創建一個對象:

public class User{

private int id;

private String name;

private Date birthday;

//省略了get/set方法

}

編寫映射文件:User.hbm.xml

<hibernate-mappingpackage="cn.itcast.hibernate.domain">

在配置文件中hibernate.cfg.xml:

<propertyname="connection.url">jdbc:mysql://localhost:3306/jdbc

<propertyname="connection.username">root

<propertyname="connection.password">

org.hibernate.dialect.MySQLDialect

<propertyname="hbm2ddl.auto">

<mappingresource="org/hibernate/test/legacy/User.hbm.xml"/>

<class-cacheclass="org.hibernate.test.legacy.Simple" region="Simple"usage="read-write"/>

方言dialect就是哪一種數據庫.hibernate本身能夠創建表(hbm2ddl.auto)

(6).初始化:

Configuration cfg = new Configuration();

cfg.configure();

SessionFactory sf=cfg.buildSessionFactory();//SessionFactory至關於JDBC中DriverManager

Session s=sf.openSession();//工廠模式,生產connection

Transaction tx=s.beginTransaction();

User user = new User();

user.setBirthday(new Date());

user.setName("name");

s.save(user);

ts.commit();

s.close();

(7).hibernate默認會把事務自動提交功能關閉了,全部本身要手動打開,查看錶的結構命令:show create table user,看錶的引擎是否支持事務,查看引擎命令:show engines

(8).開發流程:

方式一:由Domain object->mapping->db

方式二:由DB開始,用工具生成mapping和Domain object

方式三:由映射文件

(9).hibernate管理的Domain對象類定義必需要符合JavaBean的定義規則:默認的構造方法(必須的),有無心義的標示符id(主鍵),非final的,對懶加載有影響

public class User{

private int id;

private String name;

private Date birthDay;

//get/set方法

}

10.編寫一個工具類進行初始化Hibernate

public final class HibernateUtil{

private static SessionFactorysessionFactory;

private HibernateUtil(){

}

static{//靜態代碼塊

Configuration cfg = new Configuration();

cfg.configure();//默認的傳入是hibernate.cfg.xml文件

sessionFactory = cfg.buildSessionFactory();

}

public static SessionFactorygetSessionFactory(){

return sessionFactory;

}

}

11.static void addUser(User user){//標準規範代碼

Session s=null;

Transaction tx=null;

try{

s=HibernateUtil.getSession();

tx.s.beginTransaction();

s.save(user);

tx.commit();

}catch(HibernateException e){

if(tx!=null)

tx.rollback();//不只要回滾,還有拋出異常

throw e;

}finally{

if(s!=null)

s.close();

}

}

6.hibernate配置文件中的配置項

(1).hibernate.cfg.xml和hbm.xml內容解釋:

第一:數據類型: type能夠是hibernate、java類型或者你本身的類型(須要實現hibernate的一個接口)

第二:基本類型通常不須要在映射文件中說明,只有在一個java類型和多個數據庫數據類型相對應時而且你想要的和hiberante缺省映射不一致 時,須要在映射文件中指明類型(如:java.util.Date,數據庫 DATE,TIME,DATATIME,TIMESTAMP,hibernate缺省會把java.util.Date映射成DATATIME型),而如 果你想映射成TIME,則你必須在映射文件中指定類型

第三:數據類型的對應關係

(2).Session是非線程安全的,生命週期短,表明一個和數據庫的鏈接,在B/S系統中通常不會超過一個請求;內部維護以及緩存和數據庫鏈接,若是session長時間打開,會長時間佔用內存和數據庫鏈接

(3).SessionFactory是線程安全的,一個數據庫對應一個SessionFactory,生命週期長,通常在整個系統生命週期內有 效;SessionFactory保存着和數據庫鏈接的相關信息(user,password,url)和映射信息,以及Hibernate運行時要用到 的一些信息.

7. Hibernate映射類型

serializable:序列化到數據庫中.

8.Hibernate中使用的集合類型

(1).集合映射(set,list,array,bag,map)

List emps = new ArrayList ();

映射文件中:

<listname="emps">

配置和set標籤是相同的,只是區分List,Set的區別

<list-indexcolumn="order_col"/>這一列是給hibernate使用的,須要記錄該員工是第幾個加進來的,即加入的順序.

(2).因爲懶加載的問題,Hibernate重寫了java中的集合類,使其具備懶加載的功能.因此在定義的時候,必需要定義成接口類型即List,Set,Map

9.hql的命名參數與Query接口的分頁查詢

(1).匿名參數:不使用佔位符了

String hql ="from User as user where user.name=:n";

query.setString("n",name);

不會依賴參數的位置

(2).Query接口中的方法

query.setFirstResult(0);

第一條記錄從哪開始,參數爲開始的位置

query.setMaxResult(10);

實現分頁功能

10.Hql與Criteria查詢的補充知識

HQL:查詢多個對象select art,user from Article art,User user where art.author.id=user.idand art.id=:id這種方式返回的是Object[],Object[0]:article,Object[1]:user;

11.Iterate查詢與N+1次查詢

(1).假設已經加入到了10個用戶

static void iterator(){

Session s=HibernateUtils.getSession();

Query q=s.createQuery("fromUser");

Iterator users =q.iterate();

while(users.hasNext()){

System.out.println(users.next().getName().getFirstName());

}

}

首先把10個用戶的id都查詢出來,而後按照id去查詢詳細信息,這是會到一級緩存中查找,找不到在到二級緩存,找不到在到數據庫中查找.假設都到 數據庫中查詢,那麼就進行了11次查詢,第一次把全部的id都查詢,而後再逐一按照id查詢進行10次,總共進行了11次,因此在使用時必定要當心,是否 肯定一級緩存和二級緩存中有咱們想要查詢的數據,否則的話,性能就降低了

(2).在懶加載的狀況下,就會出現N+1次查詢,好比一對一:

首先查詢IdCard獲得id,而後再去訪問Person

Session s=HibernateUtil.getSession();

Query q=s.createQuery("fromIdCard");

List ics=q.list();

for(IdCard> ic:ics){

System.out.println(ic.getPerson().getName());

}

由於懶加載,每次訪問數據的時候,都進行查詢數據庫.

12.load方法的懶加載及原理分析

(1).Useruser=(User)s.load(userClass,id);

System.out.println(user.getClass());

就是說s.load(userClass,id)返回的是User的一個代理對象.便是User的子類.在session沒有關閉前,去訪問數據庫 user.getName();可是這種方式很差,最好使用Hibernate.initialize(user);初始化懶加載.

(2).懶加載是將與數據庫的交互延遲,提升性能.load()方法,不會到數據庫查詢,只會返回一個User的一個子類.

(3).asm.jar,cglib.jar這兩個包實現懶加載,可以動態的修改內存中的字節碼.即動態的生成一個User的子類.

(4).employee.setUser(user);這是就能夠使用懶加載,創建employee和user之間個關聯,可是不須要去訪問數據庫的時候

(5).經過asm和cglib兩個包實現的,Domain是非final的,session.load懶加載

one-to-one懶加載:必須知足三個條件才能實現懶加載:第一:主表不能有constrained=true,因此主表沒有懶加載,第二:lazy!=false,第三:fetch=select;

one-to-many懶加載:第一:lazy!=false,第二:fetch=select

many-to-one:第一:lazy!=false,第二:fetch=select

many-to-many:第一:lazy!=false,第二:fetch=select

(6).可以懶加載的對象都是被改寫過的代理對象,當相關聯的session沒有關閉時,訪問這些懶加載對象(代理對象)的屬性(getId和 getClass除外),hibernate會初始化這些代理,或用Hibernate.initialize(proxy)來初始化代理對象,當相關聯 的session關閉後,再訪問懶加載的對象將出現異常.

(7).方法getId和getClass不須要訪問數據庫也是知道的,因此不是出現懶加載的初始化異常.

(8).表中的屬性也能夠使用懶加載的,只是須要在編譯後的內容進行處理,這種用途主要在字段是大文本類型時須要.

13.OpenSessionInView模式的代碼分析

(1).ThreadLocal類

private static ThreadLocal session=newThreadLocal();

線程級變量,做用域在一個線程內.

Session s=(Session)session.get();

if(s==null)}

s=getSession();

session.set(s);

}

當有一個web請求來時,服務器建立一個線程進行服務,將建立一個session,因此在這個線程內能夠訪問到session

(2).sessioncontext和事務邊界

用current_session_context_class屬性來定義context(用sessionFactory.getCurrentSession()來得到session),其值爲:

第一:Thread:ThreadLocal來管理Session實現多個操做共享一個Session,避免反覆獲取Session,並控制事務邊 界,此時session不能調用close,當commit或rollback的時候session會自動關閉 (connection.realease_mode:after_transaction).Opensession in view:在生成(渲染)頁面時保持session打開,前面所說的懶加載時,能夠保證session沒有關閉,能夠訪問到數據.

第二:由JTA事務管理器來管理事務(connection.release_mode:after_statement)

(3).用戶發送請求->web容器->doFilter(過濾器)->OpenSessionView->打開 session,事務->ActionServlet(struts)的service方法->根據配置文件找到 ->Action(execute方法)->業務邏輯層(register方法)->Dao層(addUser方法)->返回, 直到doFilter的commit,提交事務.在這個過程當中session都沒有關閉,能夠解決事務的邊界問題,解決懶加載的問題(即何時使用懶加 載).缺點:延長事務,session的生命週期,session延遲關閉,那麼一級緩存不會釋放,長時間佔用內存.客戶端的網速比較慢,致使事務和 session長時間不能關閉.即延遲關閉.會給服務器端形成很大的負載.

14.Session接口及getloadpersist方法

(1).因爲Session能夠管理多個數據庫表對應的多個實體對象,若是要查詢id爲1的實體對象,Session.get方法須要知道去哪一個數 據庫表中查詢id爲1的記錄,因此,除了給get方法傳遞所要查詢的實體對象的id值外,還必須給get方法傳遞實體對象的類型,get方法才能知道去哪 個數據庫表中進行查詢

(2).經過類的類型能夠去hibernate.cfg.xml文件中查找到對應的表

(3).在配置文件中添加標籤<propertyname="show_sql">true//能夠打印sql語句

(4).Useruser=(User)s.get(userClass,id);與User user=(User)s.load(userClass,id);的區別,load不會去訪問數據庫,只有第一次訪問時,纔會訪問數據庫.增長一條打印 出user1的類名的代碼,就能夠看到load方法所返回的User子類的名稱了,該語句以下:

System.out.println(user1.getClass().getName());

(5).s.save(user)和s.persist(user);都是存儲數據,persist方法沒有sql語句,沒有開啓事務,save會回滾,persist不會回滾

15.Session與SessionFactory的多線程問題

Session內部封裝了一個connection對象,儘可能遲的建立鏈接,儘可能早的釋放鏈接

16.本地sql查詢與命名查詢

(1).使用Query接口

static list sql(){

Session s=HibernateUtil.getSession();

Query q = s.createSQLQuery("select * fromuser").addEntity(User.class);//查詢的結果是User對象

List rs=q.list();

for(User r:rs){

System.out.println(r.getName());

}

}

(2).不一樣的數據庫,本地的查詢語句是不一樣的,因此這種本地的查詢語句最好不要使用,兼容性和移植性很差.

(3).命名查詢:將查詢語句放在配置文件中,之後修改查詢語句只修改配置文件中的查詢語句就能夠了.

<queryname="getUserByBirthday">

<[CDATA[from User wherebirthday=:birthday]]>

這個定義能夠放到class標籤內部,不須要使用全名,只須要getUserByBirthday便可,可是在這個範圍內,不能出現重名,若是在外部,那就須要全名了,cn.itcast.hibernate.domain.User.getUserByBirthday

在配置文件中

static List namedQuery(){

Session s=HibernateUtil.getSession();

Queryq=s.getNamedQuery("getUserByBirthday");

q.setDate("birthday",new Date());

return q.list();

}

(4).hibernate能夠作到用Map代替Domain對象,存入到數據庫,可是這就符合ORM定義了,同時也能夠將數據庫中的內容轉換XML

17.多對多關聯關係的查詢

使用表之間的關聯join,效率低

18.多對多關聯關係的映射與原理分析

(1).多對多(teacher-student):在操做和性能方面都不太理想,因此多對多的映射使用較少,實際使用中最好轉換成一對多的對象模型;Hibernate會爲咱們建立中間關聯表,轉換成兩個一對多.

ER圖:teacher:id(PK);student:id(PK);teacher_student:teacher_id(PK,FK1),student_id(PK,FK2)

(2).

public class Teacher{

private int id;

private String name;

private Set students;

//省略get/set方法

}

public class Student{

private int id;

private String name;

private Set teachers;

//省略get/set方法

}

teacher的映射文件:

根據student_id去查詢學生的相關信息

同理student的映射文件類似.

(3).測試類:

Set ts=newHashSet ();

Teacher t1=new Teacher();

t1.setName("t1 name");

Teacher t2=new Teacher();

t2.setName("t2 name");

ts.add(t1);

ts.add(t2);

Set ss=newHashSet ();

Student s1=new Student();

s1.setName("s1");

Student s2=new Student();

s2.setName("s2");

t1.setStudents(ss);//創建關聯關係

t2.setStudents(ss);

ss.add(s1);

ss.add(s2);

s.save(t1);

s.save(t2);

s.save(s1);

s.save(s2);

在中間表中插入數據

19.多對一的懶加載分析

(1).查詢員工的信息時,是否須要部門的信息,默認的狀況下是懶加載的方式,怎樣判斷是否進行了懶加載,能夠經過打印出的sql語句中的查詢語句便可

(2).當IdCard中的id是主鍵也是外鍵,當id有值時,必定有一個person與之對應,因此能夠使用懶加載,先生成一個代理對象,當須要 person的信息時,纔去查詢,反過來,由於person中的id只是個主鍵,知道person的id,IdCard中不必定有一個值與之對應,因此不 使用懶加載的方式,而是直接去查詢數據庫,這就是查詢主表時不使用懶加載,查詢從表時使用懶加載.

(3).可是多對一的部門和員工,直接就是用了代理,depart.getEmps()獲取員工時,Hibernate中的集合把集合空對象和空集合是相同的概念.

20.多對一關聯關係的檢索與原理分析

(1).查詢操做(department表的查詢和之前同樣,只是employee表不同):

static Employee query(int empid){

Employee emp =(Employee)s.get(Employee.class,empid);

System.out.println("departname:"+emp.getDepart().getName());//獲得department的名稱.

return emp;

}

進行兩次查詢,首先根據id查詢employee表,獲得depart_id,在根據depart_id查詢department表.

21.多對一關聯關係的映射與原理分析

(1).多對一:映射文件:

ER圖中定義Employee主鍵(PK):id和外鍵(FK):depart_id,Department的主鍵id;

(2).創建Department類

public class Department{

private int id;

private String name;

//省略get/set方法

}

創建Employee類

public class Employee{

private int id;

private String name;

private Department depart;

//省略get/set方法

}

(3).映射文件:

<hibernate-mappingpackage="cn.itcast.hibernate.domain">

不在使用標籤property,是對象類型depart,使用標籤

經過反射能夠找到depart對應的映射文件,當depart_id與depart映射文件中的id相同時,就查找到了.也能夠使用屬性not-null="true",設置colum="depart_id"這列不爲空

(4).column="depart_id"不設置能夠,默認就是column="depart"

(5).staticDepartemnt add(){

//模板代碼,省略

Department depart = new Department();

depart.setName("depart name");

Employee emp = new Employee();

emp.setDepart(depart);//直接賦值就能夠了,只要在對象創建關係,數據庫中的表就創建關係了.

emp.setName("emp name");

s.save(depart);

s.save(emp);

return depart;

}

(6).當s.save(depart);與s.save(emp)兩條語句的順序調換,會多出現一條更新語句,由於首先存儲emp,當存儲到 depart時,由於employee中定義了department,因此hibernate檢測到employee中的depart發生改變了,就進行 了更新操做.此時是持久態

22. 分佈式緩存的分析

大型網站有多個服務器,即就有多個cache,每一個服務器對應一個cache,

23.關聯關係的級聯操做

(1).cascade和inverse:

Casade用來講明當對主對象進行某種操做時是否對其關聯的從對象也作相似的操做,經常使用的cascade:none,all,save- update,delete,lock,refresh,evict,replicate,persist,merge,delete- orphan(one-to-many),通常對many-to-one,many-to-many不設置級聯,在one-to-one和one-to- many中設置級聯

Inverse表「是否放棄維護關聯關係」(在Java裏兩個對象產生關聯時,對數據庫表的影響),在one-to-many和many-to- many的集合定義中使用,inverse="true"表示該對象不維護關聯關係;該屬性的值通常在使用有序集合時設置成false(注意 hibernate的缺省值是false),one-to-many維護關聯關係就是更新外鍵,many-to-many維護關聯關係就是在中間表增減記 錄

注:配置成one-to-one的對象不維護關聯關係.

24.緩存的原理與模擬分析

(1).第一我的讀的信息和後一我的讀的信息可能相同,那第二我的讀信息時可以加快速度了.

(2).第二人讀取信息時,就不是到數據庫中讀取了,能夠到緩存中讀取數據.

(3).使用緩存cache存取數據.

25.繼承_鑑別器與內鏈接器相結合

(1).子類的特有屬性不少,就拿一張表進行對應,特有屬性少的就和父類放在同一個表中,

(2).employee:id(PK),name,depart_id,type,skill;sales:employee_id(PK,FK),sales;

Skiller子類和Employee父類放在一塊兒,Sale類本身對應一張表.

(3).映射文件中只需按照前兩中方式進行改變.

26.繼承_每一個具體類映射一張獨立表

(1).沒有公共的屬性,全部的屬性都是本身特有的,在插入時候不須要涉及到多個表的關聯了,效率高.若是employee不是抽象的,會有employee表

(2).employee:id(PK),name,depart_id;skiller:id(PK),name,skill,depart_id;sales:id(PK),name,sell,depart_id;

(3).映射文件:

(4).在查詢的時候,多態查詢時,仍是要進行三種表的關聯查詢,可是插入只在一張表進行.

27.繼承關係_每一個類映射到一張表

(1).employee:id(PK),name,depart_id;sales:employee_id(PK,FK),sell;skiller:employee_id(PK,FK),skill;

(2).此時不須要鑑別器了,每一個子類對應一張表

(3).映射文件:

<joined-subclassname="Skiller" table="skiller">

(4).插入子類時,相同的屬性插入到employee表中,本身特有的屬性插入到本身表中,若是插入一個技術員Skiller(name,skill)時skill插入skiller表中,name插入employee表中,這時就插入了兩張表.

(5).當查詢本身特有的屬性時,會關聯兩張表,當查找相同的屬性時,會關聯三張表.因此查詢時效率低.不要進行多態查詢,最好查詢具體的子類:

具體查詢:Employee emp = (Employee)s.getId(Skiller.class,id);

多態查詢:Employee emp = (Employee)s.getId(Skiller.class,id);

28.繼承關係_整個繼承樹映射到一張表

(1).public classSkiller extends Employee{

private String skill;

//省略get/set方法

}

public class Sales extends Employee{

private int sell;

//省略get/set方法

}

(2).employee表中的字段:id(PK),name,depart_id,type(區分不一樣類型的員工,又稱鑑別器),skill,sell

(3).這種方式當增長子類時,須要修改employee表結構.

(4).映射文件:

鑑別器,hibernate用來區分不一樣的子類.

(5).將一棵繼承樹映射到一張表中,因此在查詢時,只對一張表進行操做,效率高,可是不靈活,當增長子類時,須要更改表結構,同時每一個字段不能設置成非空約束.

29.實體對象的三種狀態與saveOrUpdate方法

(1).Session的幾個主要方法:

第一:save,persist保存數據,persist在事務外不會產生insert語句

第二:delete:刪除對象

第三:update:更新對象,若是數據庫中沒有記錄,會出現異常

第四:get:根據ID查詢數據,會馬上訪問數據庫

第五:load:根據ID查詢,(返回的是代理,不會當即訪問數據庫)

第六:saveOrUpdate,merge(根據ID和version的值來肯定是save或update),調用merge你的對象仍是託管的

第七:lock(把對象編程持久對象,但不會同步對象的狀態)

(2).瞬時(transient):數據庫中沒有數據與之對應,超過做用域會被JVM垃圾回收器回收,通常是new出來且與session沒有關聯的對象

持久(persistent):數據庫中有數據與之對應,當前與session有關聯,而且相關聯的session沒有關閉,事務沒有提交;持久對象狀態發生改變,在事務提交時會影響到數據庫(hibernate能檢測到)

脫管(detached):數據庫中有數據與之對應,但當前沒有session與之關聯;託管對象狀態發生改變,hibernate不能檢測到.

(3).當關閉session時,持久態就變成了脫管狀態了,區分這三種狀態的兩個標準:是否與數據庫中記錄相對應,是否在session中.

(4).當在脫管的狀態時,更新的時候須要執行update的更新語句,由於不在session中.

(5).對象new是瞬時的,get(),load(),find(),iterate()等是持久的,瞬時狀態執行 save(),saveOrUpdate()時變成持久的,當持久狀態執行delete()時變成瞬時的,當脫管狀態執行 update(),saveOrUpdate(),lock()時變成持久狀態,當持久狀態執行evict(),close(),clear()時,持久 狀態變成脫管狀態.

(6).瞬時對象的id沒有值,脫管對象的id是有值的.因此當沒有值時執行save()方法,當有值時執行update()方法.

30.實體類或屬性名與數據庫關鍵字衝突問題

使用Oracle時,user是個關鍵字,可能出現問題,將表名添加反引號.

31.使用Hibernate完成CRUD實驗的步驟說明

(1).實驗步驟:

第一步:設計domain對象User

第二步:設計UserDao接口

第三步:加入hibernate.jar和其依賴的包

第四步:編寫User.hbm.xml映射文件,能夠基於hibernate/eg目錄下的org/hibernate/auction/User.hbm.xml修改

第五步:編寫hibernate.cfg.xml配置文件,能夠基於hibernate/etc/hibernate.cfg.xml修改;必須提 供的幾個參數:connection.driver_class、connection.url、connection.username、 connection.password、dialect、hbm2ddl.auto

第六步:編寫HibernateUtils類,主要用來完成hibernate初始化和提供一個得到Session的方法

第七步:實現UserDao接口

32.事務的悲觀鎖和樂觀鎖

(1).悲觀鎖和樂觀鎖

悲觀鎖由數據庫來實現;樂觀鎖hibernate用version和timestamp來實現,悲觀鎖就至關於寫鎖,當本身在操做時,別人不能進行任何操做,

(2).可能多我的來讀取同一個數據源,可能後一我的修改後的結果覆蓋前一我的修改的結果,存在併發問題

(3).悲觀鎖是不可取的,咱們給每條記錄添加一個版本號,當同時操做數據源時,判斷版本號,若是版本號不符合,就不進行更新.假設剛開始版本號爲 0,同時來兩我的進行操做,判斷版本號是否爲0,若是爲0,就進行操做,操做完後版本號加一,那第二我的就發現版本號不等於0,就不會進行操做了,也不會 覆蓋前一我的進行的操做.

(4).在映射文件中:

<versionname="ver"/>該標籤必須在id標籤的下面,便是id的子標籤.

(5).版本號的類型是整型的,也能夠是日期型的

(6).

Session s1=HibernateUtil.getSession();

Transactiontx1=s1.beginTransaction();//第一個線程操做事務

User user1=(User)s1.get(User.class,id);

Session s2 =HibernateUtil.getSession();

Transactiontx2=s2.beginTransaction();//第二個線程操做事務

User user2=(User)s2.get(User.class,id);

user1.getName().setFirstName("firstName1");

user2.getName().setFirstName("firstName2");

tx2.commit();//線程二先提交,成功了

tx1.commit();//線程一提交不成功.由於版本號不同.

33.事務與事務邊界的相關知識

(1).一個SessionFactory對應一個數據庫,由JDBC實現

(2).事務的控制應該在業務邏輯層實現.可是事務的對象是在DAO層,那麼在業務邏輯層中調用事務的對象,就出現了耦合,因此要解決這個耦合,就需藉助第三方架包了EJB,Spring

34.完善HibernateUtil類及hql查詢入門

(1).HQL:面向對象的查詢語言,與SQL不一樣,HQL中的對象名是區分大小寫的(除了Java類和屬性其餘部分不區分大小寫),HQL中查的 是對象而不是和表,而且支持多態;HQL主要經過Query來操做,Query的建立方式:Query q=session.createQuery(hql);

from Person

from User as userwhere user.name=:name//其中User是類不是表名,user是別名

form User as userwhere user.name=:name and user.birthday<:birthday

(2).Criteria:是一種比HQL更面向對象的查詢方式;Criteria的建立方式:Criteria crit=session.createCriteria(DomainClass.class);

簡單屬性條件如:

criteria.add(Restrictions.eq(propertyName,value)),criteria.add(Restrictions.eqProperty(propertyName,otherPropertyName))

(3).public staticvoid add(Object entity){//可以保存全部對象

Session s=null;

Transactiontx=null;

try{

s=HibernateUtil.getSession();

tx.s.beginTransaction();

s.save(entity);

tx.commit();

}catch(HibernateExceptione){

if(tx!=null)

tx.rollback();//不只要回滾,還有拋出異常

throw e;

}finally{

if(s!=null)

s.close();

}

}

同理更新,刪除同時一樣的道理

(4).執行HQL語句

Session s=null;

try{

s=HibernateUtil.getSession();

Stringhql="from User as user where user.name=?";

Queryquery=s.createQuery(hql);

query.setString(0,name);//替換佔位符

Listlist=query.list();//JDBC中的executQuery()相似

for(Useruser:list{

System.out.println(user.getName());

}

//Object obj=query.uniqueResult();當肯定返回值只有一個的時候,使用這種方法.當查詢有多個結果時,會出現異常

}finally{

if(s!=null)

s.close();

}

支持多態,查詢的話,子類對應數據庫表也被查詢,若是from Object的話,會把數據庫中的表都查一遍,由於全部的類都是Object的子類.

35.一對多關聯關係的映射與原理分析

(1).在Department的角度上是否是一對多了,在Department中定義:

privateSet emps;//一個department中有多個員工

(2).映射文件:

<classname="Department">

<idname="id">

<generatorclass="native"/>

<propertyname="name"/>

<setname="emps">用set屬性進行映射

<keycoluem="depart_id"/>設置外鍵

<one-to-manyclass "Employee"/>

(3).System.out.println("empsize:"+depart.getEmps().size());

打印出department中全部的employee人數.

(4).首先添加employee,在添加到department,即告訴employee屬於哪一個department;多兩條更新語句.

Set emps = new HashSet ();

emps.add(emp1);

emps.add(emp2);

depart.setEmps(emps);

告訴department有哪些employee

emp1.setDepart(depart);

emp2.setDepart(depart);

(5):ER圖:Deparment:id(PK);Employee:id(PK),depart_id(FK1);

36.一對多和多對多的懶加載分析

(1).對於one-to-one懶加載方式體現出的效率不是很明顯,查詢身份證號時,把person的信息也查詢出來,沒有查詢太多的信息,對效率的影響不是很大

(2).對於one-to-many懶加載方式就體現的很明顯的了,當咱們查詢部門的詳細信息時,可能把該部門的全部員工都查詢出來,由於一個部門可能有不少員工,因此這時效率就明顯下降了.

(3).缺省的是懶加載,當depart.getEmps()時,纔會查詢員工的信息,由於java中的set集合沒有懶加載的功能,當咱們的代碼 只是獲取集合代理對象的引用,比沒有調用該集合代理對象的方法,因此,hibernate在這裏還用不着去查詢數據庫來填充集合代理,所以不會拋出"代理 未初始化"的異常,若是將代碼改成depart.getEmps().size(),就能夠看到異常了.

(4).對於many-to-many方式懶加載也很重要,由於涉及到三張表的查詢.因此也須要懶加載的功能.

37.一對一的懶加載分析

(1).one-to-one在查詢主對象的時候默認狀況下不使用懶加載,使用一個關聯查詢.可是在查詢從對象的時候使用了懶加載.

(2).constrain=true是創建外鍵約束

(3).lazy="proxy",使用懶加載,默認的值也是proxy,還有false,true的取值

(4).fetch="join",使用什麼方式去抓取,默認值爲select,join是一次查詢(表的鏈接),select是兩次查詢.當lazy="proxy"時,fetch="join"是無效的,它們倆之間的設置是互斥的.

38.一對一外鍵關聯關係的映射與原理分析

(1).一對一:基於外鍵的one-to-one,能夠描述爲多對一,加上unique="true"約束 <many-to-onename="person" column="person_id" unique="true"not-null="true"/>區別於多對一.只需將外鍵設置爲惟一.

(2).對於IdCard的映射文件,其的id不是外部生成的,而是自增加的.

<generatorclass="native"/>對於Person的映射文件:

39.一對一主鍵關聯關係的檢索

(1).查詢主對象:

Personp=(Person)get(Person.class,id);

System.out.println(p.getIdCard().getId());

理論上是兩次查詢,可是實際只進行了一次查詢,使用了表之間的關聯join,效率上比兩次查詢高

查詢從對象:

IdCardidCard=(IdCard)get(IdCard.class,id);

System.out.println(idCard.getPerson().getId());

理論上和實際上都進行了兩次查詢

40.一對一主鍵關聯關係的映射與原理分析

(1).基於主鍵的one-to-one(person的映射文件)

<generatorclass="foregin"><paramname="property">idCard

(2).對象模型:

public class Person{

private int id;

private String name;

private IdCard idCard;

//省略get/set方法

}

public class IdCard{

private int id;

private String name;

private Person person;

//省略get/set方法

}

(3).Person的映射文件:

IdCard的映射文件:

主鍵是由外部獲得,不是本身獲得的

<paramname="property">personIdCard的id是由person獲得的

添加約束,配置外鍵.

idcard中的主鍵是person中的外鍵

(4).測試代碼:

IdCard idCard = new IdCard();

Person p=new Person();

p.setName("p1");

p.setIdCard(idCard);

idCard.setPerson(p);

s.save(p);

s.save(idCard);

IdCard中的id是由Person獲得的.只有主對象(person)存在,從對象(idcard)存在.

(5).ER圖:person:id(PK);IdCard:id(PK,FK)

41.組件關聯關係的映射與原理分析

(1).組件映射(User-Name):關聯的屬性是個複雜類型的持久化類,但不是實體即:數據庫中沒有表與該屬性對應,但該類的屬性要之久保存的

當組件的屬性不能和表中的字段簡單對應的時候能夠選擇實現:

org.hibernate.usertype.UserType或

org.hibernate.usertype.CompositeUserType

(2).用戶名name是個對象類型

public Class Name{

private String firstName;

private String lastName;

//get/set方法省略

}

想過使用一對一.一對多,多對一均可以,一我的只能有一個名字,一我的能夠有多個名字.這是數據庫中確定有兩張表:User和Name,可是如今 Name的內容很小,不想設計成一個實體,不想在數據庫中對應一張表,由於它過小了,此時就是用組件相關聯,將用戶user和名字name設計到同一張表 中

6、 JDBC

1.DAO設計思想與搭建骨架

(1).創建Domain包,在包中創建一個實體對象(bean).

public class User{

private int id;

private String name;

private Date birthday;//java.util.Date

private float money;

//生成對應的get/set方法,省略

}

(2).定義Domain接口:

public interface UserDao{

public void addUser(User user);

public User getUser(int userid);

public void update(User user);

public void delete(User user);

public User findUser(StringloginName,String password);

}

這個接口是給service層使用的.

(3).實現UserDao接口

public class UserDaoImpl implements UserDao{

public void addUser(User user){};

public User getUser(int userid){};

public void update(User user){};

public void delete(User user){};

public User findUser(StringloginName,String password){};

}

(4).在UserDaoImpl中拋出的異常進行包裝,定義一個異常類

(5).工廠模式:UserDao userDao = DaoFactory.getInstance().getUserDao();

2.Java的動態代理及使用該技術完善鏈接代理

(1).前面說到的靜態代理模式,有點麻煩,由於須要實現接口Connection的全部方法.

(2).public classMyConnectionHandler implements InvocationHandler{

private Connection realConnection;

MyConnectionHandler(){

}

Connectionbind(Connection realConn){//經過此方法將鏈接傳進來

ConnectionwarpedConnection = (Connection)Proxy.newProxyInstance(this.getClass().getClassLoader(),newClass[] {Connection.class},this);//動態的編寫一個類,這個類實現Connection接口,最終會把Connection的全部方 法都交給InvocationHandler處理器處理,在內存中直接產生一個字節碼.

returnwarpedConnection;

}

public Objectinvoke(Object proxy,Method method,Object[] args){

if("close".equals(method.getName())){//是close方法

this.dataSource.connectonsPool.addList(this.warpedConnection);

}

returnmethod.invoke(this.realConnection,args);

}

}

這就是動態代理模式,無論是動態的,仍是靜態的,最終到底都是關心操做Connection的方法.

3.JdbcTemplate類中的其餘各個查詢方法

(1).Spring的JdbcTemplate

第一:查詢帶有參數,和行映射方法:

public ObjectqueryForObject(String sql,Object[]args,RowMapper rowMapper),使用自定義的UserRowMapper完成映射

一個RowMapper的經常使用實現BeanPropertyRowMapper,該實現可將結果集轉換成一個Java Bean(字段名與Java Bean屬性名不符合規範,可用別名處理)返回一條記錄.

第二:public List query(String sql,Object[]args,RowMapperrowMapper)返回多條記錄

第三:public int queryForInt(String sql)(如:selectcount(*) from user),其餘結果好比String可用queryForObject方法向下轉型

public MapqueryForMap(String sql,Object[]args)返回不是對象類型的Map(key:字段名或別名,value:列值);當查詢的結果不是一個對象時,就是用一個 Map進行存放結果.查詢共多少條記錄,最大值,最小值等信息時,當返回的是String類型時,就是用queryForObject(String sql);只是要對返回類型進行轉換.

第四:public List queryForList(String sql,Object[]args)返回多個Map

4.JDBC的理論概述

(1).JDBC(Java數據庫鏈接)由一些藉口和類構成的api,j2se的一部分,由java.sql,javax.sql包組成

(2).應用程序、JDBC API、數據庫驅動及數據庫之間的關係:

應用程序-->JDBC-->MySql Driver,Oracle Driver,DB2Driver--->MySql,ORacle,DB2

5.jdbc中數據類型與日期問題

(1).rs.getInt("id"),getString("name"),rs.getDate("birthday"),rs.getFloat("money")),不一樣的類型的獲取數據.

(2).java.sql.Date是繼承java.util.Date,java.util.Date是日期和時間的,而java.sql.Date只有日期,而沒有時間.

(3).不能將java.util.Date賦給java.sql.Date,所 以:newjava.sql.Date(birthday.getTime()));這樣就能夠將java.util.Date轉換成 java.sql.Date,java.sql.Date直接賦給java.util.Date能夠的.

(6).st.executeUpdate(sql),帶參數的方法是Statement的,不帶參數的方法是PreperedStatement的

6.JTA分佈事務的簡要介紹

(1).跨多個數據源的事務,使用JTA容器實現事務,分紅兩個階段提交

javax.transaction.UserTransactiontx=(UserTransaction)ctx.lookup("jndiName");

tx.begin();//connection1,connection2(可能來自不一樣的數據庫)

tx.commit()//tx.rollback();

(2).tomcat不支持這種容器.weblogic能夠支持.

(3).第一階段:向全部的數據庫提交事務的請求,當有事務回滾的請求,全部的數據庫都回滾,第二階段:當沒有回滾請求,就進行提交事務.

(4).分佈式事務處理.

7.Statement的sql注入問題

(1).SQL注入:PreparedStatement和Statement:

在sql中包含特殊字符或SQL的關鍵字(如:'or 1 or')時,Statement將出現不可預料的結果(出現異常或查詢的結果不正確),可用PreparedStatement來解決

PreperedStatement(從Statement擴展而來)相對Statement的優勢:

第一:沒有SQL注入的問題

第二:Statement會使數據庫頻繁編譯SQL,可能形成數據庫緩衝區溢出

第三:數據庫和驅動能夠對PreperedStatement進行優化(只有在相關聯的數據庫鏈接沒有關閉的狀況下有效)

PreparedStatement是Statement的子接口.

(2).

PreparedStatementps=null;//預處理接口,須要進行預處理,因此在構造的時候就須要SQL語句了,ps=conn.prepareStatement(sql);而Statement是在查詢的時候須要SQL語句.

Stringsql="select id,name from user where name=?";?問號是佔位符

ps.setString(1,name);將傳過來的name參數替換第一個佔位符?,在此過程當中,將name進行的處理,將特殊符號去除,當執行查詢時,不須要SQL語句了,否則會報錯,rs=ps.executeQuery();

(3).創建鏈接最消耗時間的,當程序執行屢次時,PreperedStatement比Statement除去創建鏈接的時間,前者效率高.

8.編寫一個基本的鏈接池來實現鏈接的重複使用

(1).鏈接池常用到插入和刪除,因此使用LinkedList,

public class MyDataSource{

private LinkedList connectionsPool = new LinkedList ();

public MyDataSource(){

for(int i=0;i<10;i++){//開始時建立10個鏈接

this.connectionsPool.addLast(this.createConnection());

}

}

public Connection createConnection() {//建立鏈接

returnDriverManager.getConnection(url,user,password);

}

public Connection getConnection(){//獲取鏈接

return this.connectionPool.removeFirst();

}

public void free(Connection conn){//釋放鏈接

this.connectionsPool.addList(conn);

}

}

獲得鏈接並非重複的.想重複的拿取鏈接,建立的鏈接數n<用戶取鏈接數m,便可.

(2).

private static int initCount=5;//定義初始化鏈接數

private static int maxCount=10;//最大鏈接數

private static int currentCount=0;//當前建立的鏈接數

(3).爲了保證併發操做,須要在獲取鏈接中同步:

synchronized(connectionsPool){

if(this.connctionPool.size()>0)//鏈接池中還有鏈接

return this.connectionsPool.removeFirst();

if(this.currentCount<maxCount)//當前鏈接數沒有超過最大鏈接數,能夠接着建立鏈接,

return this.createConnection();

throw new SQLException("已經沒有鏈接了");//超過了最大鏈接數,拋出異常.

}

9.編寫一個簡單的JDBC的例子

(1).鏈接數據的步驟:

第一步:註冊驅動(只作一次)

DriverManager.registerDriver(newcom.mysql.jdbc.Driver());

第二步:創建鏈接(Connection)

Connectionconn=DriverManager.getConnection("jdbc:mysql://localhost:3305/jdbc","root","");沒有密碼

第三步:建立執行SQL的語句(Statement)

Statementst=conn.createStatement();

第四步:執行語句

ResultSet rs =st.executeQuery("select * from user");

第六步:處理執行結果(ResultSet)

while(rs.next()){//遍歷行

System.out.println(rs.getObject(1)+'\t'+rs.getObject(2));//第一列,第二列

}

第七步:釋放資源

rs.close();//關閉資源和打開資源的順序是相反的

st.close();

conn.close();

10.參數的元數據信息

(1).

Connection conn=JdbcUtils.getConnection();

PreparedStatementps=null;

ResultSet rs=null;

ps.conn.prepareStatement(sql);//sql中可能含有參數(佔位符),Object[]params存儲參數,能夠動態的查看sql中含有哪些參數.

ParameterMetaDatapmd=ps.getParameterMetaData();

intcount=pmd.getParameterCount();//獲得參數的個數

for(inti=1;i<count;i++){

System.out.println(pmd.getParameterClassName(i));//獲得參數的類名

System.out.println(pmd.getParameterType(i));//獲得參數的類型

ps.setObject(i,parames[i-1]);//遍歷替換參數

}

String sql ="select * from user where name=? and birthday<? and money>?";

直接返回的類型都是String,VARCHAR

11.分析jdbc程序的編寫步驟和原理

(1).鏈接是經過底層的TCP/IP協議進行的

(2).註冊驅動:

方式一:Class.forName("com.mysql.jdbc.Driver");

推薦這種方式,不會對具體的驅動類產生依賴,類加載到內存中,會調用靜態代碼塊:

static{

try{

DriverManager.registerDriver(new Driver());

}catch(SQLException e){

throws RuntimeException();

}

}

方式二:DriverManager.registerDriver(newcom.mysql.jdbc.Driver());

會形成DriverManager中產生兩個同樣的驅動,並會對具體的驅動類產生依賴,其內部定義了一個Vector列表,將多個驅動存放到Vector中

方式三:System.setProperty("jdbc.drivers","driver1:driver2");

雖然不會對具體的驅動類產生依賴;但註冊不太方便,因此不多使用,能夠註冊多個驅動

(3).方式一接受的是一個字符串,方式二接受的是一個驅動類,因此具備依賴關係

(4).建立鏈接:

Stringurl="jdbc:mysql://localhost:3394/jdbc";

格式:jdbc:子協議:子名稱//主機名:端口/數據庫名

String user="root";

String password="";

Connectionconn=DriverManager.getConnection(url,user,password");

(5).釋放資源:數據庫創建鏈接的個數也是有限制的,當數據庫建立了多個鏈接,數據庫可能運行的很慢,可能致使數據庫崩潰,佔用系統資源.

12.分析在實際項目中該如何應用JDBC

(1).三層架構:

表示層:基於web的jsp、servlet、struts、webwork、spring web MVC等,基於客戶端的swing,swt等

業務邏輯層:Pojo(service,manager),Domain,session EJB、spring

數據訪問層:JDBC,IBatis,Hibernate,JDO,Entity Bean

層與層之間用接口隔離

13.規範和封裝JDBC程序代碼

(1).規範的代碼:

Stringurl="jdbc:mysql://localhost:2332/jdbc";

String user="root";

String password="";

Statement st=null;

ResultSet rs=null;

Connecton conn=null;

try{

Class.forName("com.mysql.jdbc.Driver");

conn=DriverManager.getConnection(url,user,password);

st = conn.createStatement();

rs=st.executeQuery("select * fromuser");

}finally{

try{

if(rs!=null)

rs.close();

}finally{if(st!=null)

try{

st.close();

}finally{

if(conn!=null)

conn.close();

}

}

}

}

(2).設計一個工具類:

public final class JdbcUtils{

private static Stringurl="jdbc:mysql://localhost:2332/jdbc";

private static String user="root";

private static String password="";

private JdbcUtils(){//不容許實例化

}

static{//驅動只註冊一次

try{

Class.forName("com.mysql.jdbc.Driver");

}catch(ClassNotFoundException e){

throw new ExceptionInitializerError(e);

}

}

public static Connection getConnection(){//建立鏈接

returnDriverManager.getConnection(url,user,password);

}

public static void free(ResultSetrs,Statement st,Connection conn){//釋放資源

try{

if(rs!=null)

rs.close();

}catch(SQLException e){

e.printStackTrace();

}finally{if(st!=null)

try{

st.close();

}catch(SQLException e){

e.printStackTrace();

}finally{

if(conn!=null)

conn.close();

}

}

}

}

}

14.將Dao中的修改方法提取到抽象父類中

(1).對於代碼的重構,焦點就是將代碼變化的部分和不變的部分分離開來.一個是sql語句不一樣,參數不一樣,提取一個超類,相同的部分,放到超類中,不一樣的部分由子類實現.

publci abstract class AbstractDao{

public void update(String sql,Object[]args){

Connection conn=null;

PreparedStatement ps=null;

ResultSet rs=null;

conn=JdbcUtils.getConnection();

ps=conn.prepareStatement(sql);

for(int i=0;i<args.length;i++){//用args參數列表,更新數據

ps.setObject(i+1,args[i]);

}

}

//args就是參數列表,

}

public class UserDaoImpl extendsAbstractDao{

public void update(User user){

String sql="update user setname=?,birthday=?,money=?,where id=?";

Object[] args=new Object[]{user.getName(),user.getBirthday(),user.getMoney(),user.getId()};

super.update(sql,args);//調用父類的update方法.

}

}

15.可更新和對更新敏感的結果集

(1).

st=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,Result.CONUR_UPDATABLE);

在讀取數據時,能夠更改數據,可更新結果集.

(2)

while(rs.next()){

rs.getObject("name");

rs.getObject("money");

String name= rs.getString("name");

if("lisi".equals(name)){

rs.updateFloat("money",200f);

rs.updateRow();//更新行

}

}

(3).這種方式不經常使用,在查詢時,把數據更改了,給人一種不明確感.

在查詢結果集時,更新數據時數據庫能不能感知到數據更新了.數據庫敏不敏感SENSITIVE

16.利用結果集元素數據將查詢結果封裝爲map

(1).將查詢結果放在map中

key:列的名稱

value:列的值

(2).

Connection conn=JdbcUtils.getConnection();

ps=conn.prepareStatement(sql);

rs=ps.executeQuery();

ResultSetMetaData rsmd =rs.getMetaData();//獲取結果集的元數據

int count= rsmd.getColumnCount();//結果有多少列

for(int i=1;i<=count;i++){//循環遍歷列

System.out.println(rsmd.getColumnClassName(i));//每一列的類型名

System.out.println(rsmd.getColumnName(i));//每一列的名稱

System.out.println(rsmd.getColumnLabel(i));//每一列的別名

}

這裏就能夠準確的獲得每一列的類型,而不像前面的都是String類型.

String[]colName=new String[count];//存放每一列的名稱

Map<String,Object> data=null;

while(rs.next()){//按行循環

data = new HashMap<String,Object>();

for(int i=0;i<colNames.length;i++){//按列循環

data.put(colNames[i],rs.getObject(colNames[i]));//根據類名獲得列的值

}

}

靈活性很是高.可以按照各類方式查詢

16.如何使用開源項目DBCP

(1).dbcpconfig.properties數據源的配置文件:

鏈接配置:

driverClassName=com.mysql.jdbc.Driver

url=jdbc:mysql://localhost:3306/test

username=root

password=root

初始化鏈接:

initialiSize=10

最大鏈接數量:

maxActive=50

最大空閒鏈接://不一樣的時間段建立的鏈接不一樣,可能出現空閒鏈接.

maxIdle=20

最小空閒鏈接:

minIdle=5

超過等待時間以毫秒爲單位 6000毫秒/1000等於60秒

maxWait=60000

//當沒有鏈接可取的時候,讓當前線程等待一段時間,在去拿鏈接

JDBC驅動創建鏈接時附帶的鏈接屬性,屬性的格式必須爲這樣:[屬性名=property;],注意:"user" 與"password"兩個屬性會被明確地傳遞,所以這裏不須要包含它們(url後面攜帶的值)

connectionProperties=userUnicode=true;characterEncoding=gbk

指定由鏈接池所建立的鏈接的自動提交狀態

defaultAutoCommit=true

driver default指定由鏈接池所建立的鏈接的只讀(read-only)狀態,若是沒有設置該值,則"setReadOnly"方法將不被調用,(某些驅動並不支持只讀模式,如:Informix)

defaultReadOnly=

driver default指定 由鏈接池所建立的鏈接事務級別(TransactionIsoation),可用值爲下列之一(詳情可見javadoc)NONE,READ,UNCOMMITTED,READ_COMMITTE

defaultTransactionIsolation=READ_UNCOMMITTED

(2).DBCP是apache的開源項目.實現了DataSource接口.Data Base Connection Pool,修改代碼須要重新編譯,打包,修改配置文件只須要重啓便可.

(3).

Properties prop = new Properties();

InputStream is =JdbcUtils.class.getClassLoader().getResource.AsStream("dbcp.property");//讀取property文件

prop.load(is);

private static DataSoruce myDataSource=null;

myDataSource=BasicDataSourceFactory.createDataSource(prop);

(4).DataSource用來取代DriverManager來獲取Connection;經過DataSource得到Connection 速度快;經過DataSource得到Connection都是已經被包裹過的(不是驅動原來的鏈接),它的close方法已經被修改了;通常 DataSource內部會用一個鏈接池來緩存Connection,這樣能夠大幅度提升數據庫的訪問速度;鏈接池能夠理解成一個可以存放 Connection的Collection;咱們的程序只和DataSource打交道,不會直接訪問鏈接池.

(5).使用dbcp須要的三個包:common-dbcp.jar,common-collections.jar,common-pool.jar

17.使用JDBCTemplate工具類簡化對象查詢

(1).Spring框架中提供了一個JdbcTemplate工具類,JdbcTemplate類對JDBC API進行了很好的封裝,這個類就像咱們本身對JDBC進行封裝同樣,只是代碼更健壯和功能更強大而已,咱們之後在實際項目中能夠使用 JdbcTemplate類來徹底替換直接使用JDBC API,這與直接使用JDBC API沒有太大的性能區別,使用JdbcTemplate類須要額外從spring開發包中導入spring.jar和commons- logging.jar包

(2).JdbcTemplate的設計思想和前面的MyDaoTemplate類是相同的

static User findUser(String name){

JdbcTemplate jdbc = newJdbcTemplate(JdbcUtils.getDataSource());//參數是拿到一個數據源

String sql = "select id,name from userwhere name=?";

Object[]args=new Object[]{name};

jdbc.queryForObject(sql,args,newRowMapper(){//行映射器

public Object mapRow(ResultSet rs,introwNum){

User user = new User();

user.setId(rs.getInt("id"));

return user;

}

});

return null;

}

//這裏能夠不須要實現行映射器,能夠用類代替:

new BeanPropertyRowMapper(User.class);便可

18.使用JdbcTemplate實現Dao和用工廠模式靈活切換實現

(1).

public class UserDaoSpringImpl implementsUserDao{

private SimpleJdbcTemplatesimpleJdbcTemplate

= new SimpleJdbcTemplate(JdbcUtils.getDataSource());

//增長用戶

public void addUser(User user){

String sql = "insert into user(name,money,birthday)values(:name,:money,:birthday);

KeyHolder keyHolder = newGeneratedKeyHolder();

SqlParameterSource param = new BeanPropertySqlParameterSource(user);

this.simpleJdbcTemplate.getNamedParameterJdbcOperations().update(sql,param,keyHoler);

user.setId(keyHolder.getKey().intValue());

}

}

//增長user的代碼減小了太多了.

delete,update等方法都是大同小異

//刪除用戶

public void delete(User user){

String sql = "delete from user whereid=?";

this.simpleJdbcTemplate.update(sql,user.getId());

//使用了可變參數的特性,不須要複雜的Map存儲參數

}

//查詢用戶

public User findUser(StringloginName,String password){

//如何簡化返回查找集

String sql = "selectid,name,money,birthday from user where name=?";

returnthis.simpleJdbcTemplate.queryForObject(sql,ParameterizedBeanProertyRowMapper.newInstance(User.class),userId);

}

//更新用戶

public void update(User user){//如何替換佔位符?

String sql ="update user setname=?,birthday=?,money=? where id=?";

this.simpleJdbcTemplate.update(sql,user.getName(),user.getBirthday(),user.getMoney(),user.getId());

//這裏也能夠使用bean屬性的參數源;

}

代碼量大大減小了.

19.使用JDBC的批處理功能

(1).和數據庫打交道的成本是很高的,當須要發送多條sql語句時,成本更高了,這時就須要使用批處理技術,將多條查詢語句打成一個包.

(2).

for(int i=0;i<10000;i++){

ps.setString();

ps.setName();

ps.addBatch();//把一條更新語句增長到包中

}

int[] a = ps.executeBatch();//執行批處理,不是ps.executeUpdate();

(3).首先將語句打包時,並非包越大越好,若是包過大的話,可能形成內存溢出,因此可能將一個打包在分紅幾個小包進行發送,不一樣的數據庫,包的最適合大小是不一樣的.

(4).並非全部的批處理都能提升性能,這和不一樣的數據庫以及數據庫驅動決定的.

(5).Hibernate就是用了批處理技術,可是它進行了一些優化技術.

20.使用JDBC調用的存儲過程

(1).存儲過程常常用在之前的兩層結構中,如今的三層結構已經就用不到了

(2).CallableStatement(從PreparedStatement繼承來的)

java代碼:

CallableStatement cs=null;

String sql="{calladdUser(?,?,?,?)}";

cs=conn.prepareCall(sql);

//替換參數

cs.registerOutParameter(4,Types.INTEGER);

cs.setString(1,"ps name");

cs.setDate(2.new java.sql.Date(System.currentTimeMills()));

cs.setFloat(3,100f);

cs.executeUpdate();

int id = cs.getInt(4);

System.out.println(id);

存儲過程:

create procedure 'jdbc'.'addUser' (in pnamevarchar(45),in birthday date,in money float,out pid int)

//in:輸入參數,out:輸出參數

begin

insert intouser(name,birthday,money)values(pname,birthday,money);

select last_insert_id() into pid;

//last_insert_id()是一個函數,最後一次插入的id號

end $$

21.使用SimplejdbcTemplate和泛型技術簡化代碼

(1).

public class SimpleJdbcTemplateTest{

static SimpleJdbcTemplate simple = newSimpleJdbcTemplate(JdbcUtils.getDataSource());

static T find(String nameClass clazz){

String sql = "selectid,name,money,birthday from user where name=? and money=?";

User user =

simple.queryForObject(sql,ParameterizedBeanPropertyRowMapper.newInstance(User.class),name,100f);

}//使用了可變參數功能,沒有使用了參數數組,參數Map;使用泛型,將查詢的類型也當作是參數傳遞過來.

}

(2).它的內部也是包裝了NamedParameterJdbcOperations類,當將對象可變參數變成數組後,剩下的工做都交給NamedParameterJdbcOperations類作.

simple.getNamedParameterJdbcOperations()獲取NamedParameterJdbcOperations對象

simple.getJdbcOperations()獲取JdbcTemplate對象

22.使用策略模式對模板方法設計模式進行改進

(1).對於不一樣的查詢語句,返回的結果集可能不一樣,只要一個name,可是把全部的信息都查詢出來了,這就要求不一樣的映射結果.

public StringfindUserName(int id){

Stringsql="select name from user where id=?";

Object[]args=newObject[]{id};

}

protected ObjectrowMapper(ResultSet rs){//重新覆蓋rowMapper方法

returnrs.getString("name");

}

這種方式可能致使有多少條不一樣的查詢語句,就須要覆蓋多少次rowMapper方法.

(2).java中是不容許傳遞方法的,可是能夠傳遞一個類,接口

根據不一樣的sql中的內容,查詢的列不一樣,如:

select name fromuser:能夠獲得name一列

select id,namefrom user:能夠獲得id,name這兩列

selectid,name,money from user:能夠獲得id,name,money這三列.

public classMyDaoTemplate{

public Objectfind(String sql,Object[]args,RowMapper rowMapper){

obj =rowMapper.mapRow(rs);//映射的過程由一個接口去作

}

}

public interfaceRowMapper{//定義一個行映射器接口

public ObjectmapRow(ResultSet rs);

}

public classUserDaoImpl2{

MyDaoTemplate template= new MyDaoTemplate();

public UserfindUser(String loginName,String password){

Stringsql="select id,name,money,birthday from user where name=?";

Object[] args =new Object[]{loginName};

Object user =this.template.find(sql,args,new UserRowMapper());

retrun (User)user;

}

}

classUserRowMapper implements RowMapper{

public ObjectmapRow(ResultSet rs){//行映射器

User user = newUser();

user.setId(rs.getInt("id"));

user.setName(rs.getString("name"));

user.setMoney(rs.getFloat("money"));

return user;

}

}

//當須要不一樣的查詢結果集,只需實現RowMapper接口就好了(能夠使用匿名內部方式實現)

(3).這是一種策略模式,根據不一樣的功能,調用不一樣的方法(策略),實現類組合的方式(在UserDaoImpl2類中定義一個MyDaoTemplate類)實現的,模板模式是根據繼承的方式實現的.

23.使用模板方法設計模式處理DAO中的查詢方法

publc abstractclass AbstractDao{

public Object find(String sql,Object[]args){//相同的部分在父類中實現

Connectionconn=null;

PreparedStatementps=null;

ResultSet rs=null;

conn=JdbcUtils.getConnection();

ps=conn.prepareStatement(sql);

for(inti=0;i<args.length;i++){

ps.setObject(i+1,args[i]);

}

rs=ps.executQuery();

Object obj-null;

while(rs.next()){

obj=rowMapper(rs);

}

return obj;

}

abstract protectedObject rowMapper(ResultSet rs);//父類中不知道具體的查詢結果集.放到子類實現該方法.

}

public classUserDaoImpl extends AbstractDao{

public UserfindUser(String loginName,String password){//不變的部分放到子類實現.

Stringsql="select id,name,money,birthday from user where name=?";

Object[] args =new Object[]{loginName};

Object user = super.find(sql,args);

return (User)user;

}

@Override

protected ObjectrowMapper(ResultSet rs){//在子類中知道查詢結果有幾列

User user=newUser();

user.setId(rs.getInt("id"));

user.setName(rs.getString("name"));

user.setMoney(rs.getFloat("money"));

user.setBirthday(rs.getDate("birthday"));

return user;

}

}

假設如今有一個帳戶AccountDao

public classAccountDaoImpl extends AbstractDao{

public UserfindAccount(int id){//不變的部分放到子類實現.

Stringsql="select id,name,money from account where id=?";

Object[] args =new Object[]{id};

Object user =super.find(sql,args);

return(Account)account;

}

@Override

protected ObjectrowMapper(ResultSet rs){//在子類中知道查詢結果有幾列

Accountaccount=new Account();

account.setId(rs.getInt("id"));

account.setName(rs.getString("name"));

account.setMoney(rs.getFloat("money"));

return account;

}

}

public classAccount{

private int id;

private Stringname;

private floatmoney;

//get/set方法省略

}

模板模式,相同的步驟放到父類中,不一樣的步驟放到子類中設計,service方法,doGet(),doPost()方法,首先調用service方法.service會根據method參數的值來調用doGet(),doPost()方法.

24.使用支持命名參數的JdbcTemplate

(1).Spring的NamedParameterJdbcTemplate

第一:NamedParameterJdbcTemplate內部包含了一個JdbcTemplate,因此JdbcTemplate能作的事情 NamedParameterJdbcTemplate都能幹,NamedParameterJdbcTemplate相對於JdbcTemplate主 要增長了參數能夠命名的功能

第二:public Object queryForObject(String sql,MapparamMap,RowMapper rowMapper)

第三:public Object queryForObject(Stringsql,SqlParameterSoruce paramSource,RowMapper rowMapper)

SqlParameterSource的兩個主要實現MapSqlParameterSource和BeanPropertySqlParameterSource

第四:public int update(String sql,SqlParameterSourceparamSource,KeyHolder generatedKeyHolder)保存數據得到主鍵

(2).在傳遞參數時,須要將參數Object[]args與?佔位符的位置對應好,若是對應錯了,就會出現問題,這時,咱們就能夠給佔位符起個別名

staticNamedParameterJdbcTemplate named = new NamedParameterJdbcTemplate();

Stringsql="select id from user where name=:n and money>:m andid<:id";

Map params=newHashMap();//使用Map存放參數,而不是數組了

params.put("n",user.getName());

params.put("m",user.getMoney());

params.put("id",user.getId());

/Object[]args=new Object[]{user.getName(),user.getMoney(),user.getId()};/

Object u =named.queryForObject(sql,params,new BeanPropertyRowMapper(),User.class));

//注意sql的書寫,將佔位符?替換了,注意替換的規則.NamedParameterJdbcTemplate只幹了一件事,就是將佔位符?替換成變量名,將參數命名話後,以後的操做都會交給JdbcTemplate處理.

(3).爲何要使用命名參數:

SqlParameterSourceps = new BeanPropertySqlParameterSource(user);//關於user的bean參數源

Stringsql="select id from user where name=:name and money>:money andid<:id";

Object u =named.queryForObject(sql,ps,new BeanPropertyRowMapper(),User.class));

這時參數就存放在user參數源中,參數名必須和user的屬性名同樣,將參數封裝成一個類(參數源),符合面向對象設計思想

(4).保存數據,拿到記錄的主鍵.當主鍵是符合類型(就是多列組成),也多是String類型的.

static voidaddUser(User user){

String sql ="insert into user(name,birthday,money) value(:name,:birthday,:money);

SqlParameterSourceps = new BeanPropertySqlParameterSource(user);//關於user的bean參數源

KeyHolderkeyHolder = new GeneratedKeyHolder();

named.update(sql,ps,keyHolder);

//插入的記錄的主鍵放到keyHoler中

int id =keyHolder.getKey().inValue();

user.setId(id);

Map map =keyHolder.getKeys();//主鍵由多列組成的時候

}//重點

25.事務的保存點處理

(1).當事務進行回滾時,不是所有進行回滾,有時只想回滾一部分的操做,

(2).Savepoint sp=null;

sp=conn.setSavepoint();//設置保存點

if(conn!=null&&sp!=null){

conn.rollback(sp);//將保存點當作參數,只回滾到保存點

}

26.事務的概念與JDBC事務處理

(1).事務的特性:(ACID)

原子性(atomicity):組成事務處理的語句造成了一個邏輯單元,不能只執行其中的一部分

一致性(consistency):在事務處理執行先後,數據庫是一致的(數據庫數據完整性約束)

隔離性(isolcation):一個事務處理對另外一個事務處理的影響持久性(durability):事務處理的效果可以被永久保存下來

(2).connection.setAutoCommit(false)//打開事務

connection.commit();//提交事務

connection.rollback();//回滾事務

(3).查看數據庫表的引擎是否支持事務的操做

27.事務的隔離級別

(1).當兩個事務同時去操做同一個數據源,這就是隔離性

(2).設置隔離級別:connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

隔離級別:

讀未提交:可能出現髒讀,不可重複度,幻度

讀已提交:不可能髒讀,可能出現不可重複讀,幻讀

可重複讀:不可能髒讀,不可重複讀,可能出現幻讀

可串行化:不可能髒讀,不可重複讀,幻讀

級別逐漸提升.當級別越高的時候,須要的資源越多,對併發的操做有影響.

髒讀:別人的數據沒有提交,我就讀到了.

不可重複讀:第一次讀和第二次讀的結果不一樣

幻讀:當咱們正在查詢id>10的記錄,這時有另一個事務增長一條正好id>10的記錄.

(3).隔離級別的缺省值和數據庫相關.不一樣數據庫擁有的隔離級別的個數也是不一樣的.

28.數據庫的元數據信息

(1).能夠獲得數據庫的相關信息,是否支持事務,數據庫的名稱,版本號,隔離級別等信息.

Connectionconn=JdbcUtils.getConnection();

DatabaseMetaDatadbmd =conn.getMetaData()//返回數據的元信息

dbmd.getDatabaseProductName();//獲得數據庫的名稱

(2).hibernate支持各類數據庫,因此它確定須要知道全部數據庫的相關信息.

29.經過代理模式來保持用戶關閉鏈接的習慣

(1).用戶可能不使用JdbcUtils.free()方法釋放鏈接,而是按照conn.close()方法釋放鏈接,這時咱們建立的鏈接池就沒有用了,鏈接數也就減小了,因此咱們但願用戶始終使用咱們本身編寫的方法進行釋放鏈接

(2).經過close()方法,仍是可以將鏈接方法鏈接池中,因此咱們要攔截close()方法,組合優先繼承

(3).public classMyConnection implements Connection{

private ConnectionrealConnection;//使用組合方式

privateMyDataSource dataSource;

MyConnection(ConnectionrealConnection,MyDataSource dataSource){

this.realConnection=connection;

this.dataSource=dataSource;

}

//實現Connection的全部方法

public voidclose(){//這裏就能夠實現Connection的close()方法了

this.dataSource.connectionPool.addLast(this);//把本身從新放到池中.

}

(4).此時代碼中的Connection處都使用MyConnection,這就是面向接口編程的好處.同時類MyConnection的訪問權限是包訪問權限,不許用戶訪問的,可是容許在dataSource中訪問.

(5).DataSource類和MyConnection類之間相互調用.

(6).MyConnection是個代理,是Connection的代理模式,實現Connection的close()方法.這就是靜態代理設計模式,在MyConnection類中定義一個Connection,這是組合方式,也能夠使用集成方式實現代理.

30.完成數據庫的CRUD操做

(1).書寫SQL語句時應該注意的問題:select * from user,就是不該該寫星號,最好書寫列名,獲得數據,能夠根據列的索引號,也能夠根據列名,建議使用根據列名取數據.

31.用jdbc訪問大段文本數據

(1).數據庫中的varchar最大是255個字節,因此就須要使用大文本類型TEXT.只有純文本格式才能放進去.

(2).

Stringsql="insert into clob_test(big_text) value(?)";

ps=conn.prepareState(sql);

File file=newFile("src/cn/itcast/jdbc/JdbcUtils.java");

Reader reader =new BufferedReader(new FileReader(file));//可能含有IO的異常

ps.setAsciiStream(1,reader,(int)file.length());//須要一個Reader,字符流的長度Length,這個方法只能用於文本只含有Ascii碼的

inti=ps.executeUpdate(sql);

reader.close();

rs=st.executeQuery("selectbig_text from clob_test");//讀取文本類型數據

while(rs.net()){

Clob clob =rs.getClob(1);

Reader reader =clob.getCharacterStream();

File file=newFile("JdbUtils_bak.java");

Writer writer=newBufferedWriter(new FileWriter(file));

char[]buff=newchar[1024];

for(inti=0;(i=reader.read(buff))>0;){

writer.write(buff,0,i);

}

}

writer.close();

reader.close();

7、 iBaits

優勢:

  1. ibatis把sql語句從Java源程序中獨立出來,放在單獨的XML文件中編寫,給程序的維護帶來了很大便利。

  2. ibatis封裝了底層JDBC API的調用細節,並能自動將結果集轉換成Java Bean對象,大大簡化了Java數據庫編程的重複工做。

  3. 簡單易於學習,易於使用,很是實用。

  4. 由於Ibatis須要程序員本身去編寫sql語句,程序員能夠結合數據庫自身的特色靈活控制sql語句,所以可以實現比hibernate等全自動orm框架更高的查詢效率,可以完成複雜查詢。

  5. 阿里巴巴、慧點科技等多家知名軟件公司都使用Ibatis。

缺點:

1.CRUD的操做只能帶一個參數

2.和Hibernate相比,須要編寫Sql語句,可是Hibernate不須要編寫Sql語句

相關文章
相關標籤/搜索