隨筆 - 63  文章 - 0  trackbacks - 0
          <2025年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          常用鏈接

          留言簿(2)

          隨筆分類

          隨筆檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          1.Struts 2的基本流程
            Struts 2框架由3個部分組成:核心控制器FilterDispatcher、業務控制器和用戶實現的業務邏輯組件。在這3個部分里,Struts 2框架提供了核心控制器FilterDispatcher,而用戶需要實現業務控制器和業務邏輯組件。
          2.核心控制器:FilterDispatcher
            FilterDispatcher是Struts 2框架的核心控制器,該控制器作為一個Filter運行在Web應用中,它負責攔截所有的用戶請求,當用戶請求到達時,該Filter會過濾用戶請求。如果用戶請求以action結尾,該請求將被轉入Struts 2框架處理。

          Struts 2框架獲得了*.action請求后,將根據*.action請求的前面部分決定調用哪個業務邏輯組件,例如,對于login.action請求,Struts 2調用名為login的Action來處理該請求。

          Struts 2應用中的Action都被定義在struts.xml文件中,在該文件中定義Action時,定義了該Action的name屬性和class屬性,其中name屬性決定了該Action處理哪個用戶請求,而class屬性決定了該Action的實現類。

          Struts 2用于處理用戶請求的Action實例,并不是用戶實現的業務控制器,而是Action代理——因為用戶實現的業務控制器并沒有與Servlet API耦合,顯然無法處理用戶請求。而Struts 2框架提供了系列攔截器,該系列攔截器負責將HttpServletRequest請求中的請求參數解析出來,傳入到Action中,并回調Action 的execute方法來處理用戶請求。

          顯然,上面的處理過程是典型的AOP(面向切面編程)處理方式。圖3.19顯示了這種處理模型。



          圖3.19  Struts 2的攔截器和Action

          從圖3.19中可以看出,用戶實現的Action類僅僅是Struts 2的Action代理的代理目標。用戶實現的業務控制器(Action)則包含了對用戶請求的處理。用戶的請求數據包含在 HttpServletRequest對象里,而用戶的Action類無需訪問HttpServletRequest對象。攔截器負責將 HttpServletRequest里的請求數據解析出來,并傳給業務邏輯組件Action實例。
          3.業務控制器
            正如從圖3.19所看到的,業務控制器組件就是用戶實現Action類的實例,Action類里通常包含了一個execute方法,該方法返回一個字符串——該字符串就是一個邏輯視圖名,當業務控制器處理完用戶請求后,根據處理結果不同,execute方法返回不同字符串   ——每個字符串對應一個視圖名。

          程序員開發出系統所需要的業務控制器后,還需要配置Struts 2的Action,即需要配置Action的如下三個部分定義:

          —  Action所處理的URL。

          —  Action組件所對應的實現類。

          —  Action里包含的邏輯視圖和物理資源之間的對應關系。

          每個Action都要處理一個用戶請求,而用戶請求總是包含了指定URL。當Filter Dispatcher攔截到用戶請求后,根據請求的URL和Action處理URL之間的對應關系來處理轉發。
          4.Struts 2的模型組件
            實際上,模型組件已經超出了MVC框架的覆蓋范圍。對于Struts 2框架而言,通常沒有為模型組件的實現提供太多的幫助。

          文本框: 圖3.20 控制器調用模型組件Java EE應用里的模型組件,通常指系統的業務邏輯組件。而隱藏在系統的業務邏輯組件下面的,可能還包含了DAO、領域對象等組件。

          通常,MVC框架里的業務控制器會調用模型組件的方法來處理用戶請求。也就是說,業務邏輯控制器不會對用戶請求進行任何實際處理,用戶請求最終由模型組件負責處理。業務控制器只是中間負責調度的調度器,這也是稱Action為控制器的原因。


          圖3.20顯示了這種處理流程。

          提示  在圖3.20中看到Action調用業務邏輯組件的方法。當控制器需要獲得業務邏輯組件實例時,通常并不會直接獲取業務邏輯組件實例,而是通過工廠模式來獲得業務邏輯組件的實例;或者利用其他IoC容器(如Spring容器)來管理業務邏輯組件的實例。
          5.Struts 2的視圖組件
            Struts 2已經改變了Struts 1只能使用JSP作為視圖技術的現狀,Struts 2允許使用其他的模板技術,如FreeMarker、Velocity作為視圖技術。

          當Struts 2的控制器返回邏輯視圖名時,邏輯視圖并未與任何的視圖技術關聯,僅僅是返回一個字符串,該字符串作為邏輯視圖名。

          當我們在struts.xml文件中配置 Action時,不僅需要指定Action的name屬性和class屬性,還要為Action元素指定系列result子元素,每個result子元素定義一個邏輯視圖和物理視圖之間的映射。前面所介紹的應用都使用了JSP技術作為視圖,故配置result子元素時沒有指定type屬性,默認使用JSP 作為視圖資源。

          如果需要在Struts 2中使用其他視圖技術,則可以在配置result子元素時,指定相應的type屬性即可。例如,如果需要使用FreeMarker,則為result指定值為freemarker的type屬性;如果想使用Velocity模板技術作為視圖資源,則為result指定值為velocity的type屬性……
          6.Struts 2的運行流程
            經過上面介紹,我們發現Struts 2框架的運行流程非常類似于WebWork框架的流程。

          提示  在Struts 2的官方站點,我們可以找到如下說法:Essentially,Struts 2.0 is the technical equivalent of WebWork 2.3。Aside from the package and property renaming,it isn't much different than,say,migrating from WebWork 2.1 to 2.2——意思是說:Struts 2.0技術等同于WebWork 2.3框架,除了包和屬性被改名外。從WebWork 2.2遷移到Struts 2不會比從WebWork 2.1遷移到WebWork 2.2更復雜。

          這里我們可以看到,Struts 2其實就是WebWork 2.2的升級版,這也就不難理解:為什么WebWork和Struts 2如此相似!

          因此,Struts 2的運行流程與WebWork的運行流程完全相同,讀者可以參看圖1.8來了解Struts 2的運行流程。
          posted @ 2009-04-15 14:03 lanxin1020 閱讀(1446) | 評論 (0)編輯 收藏
               摘要: 問題:         struts2 使用jakarta 上傳文件時,如果上傳文件的大小超出commons fileupload(jakarta上傳文件還是依賴commons-fileupload)設置的大小就會在進入action以前拋出異常.       &nb...  閱讀全文
          posted @ 2009-04-14 12:50 lanxin1020 閱讀(2229) | 評論 (0)編輯 收藏

           

          下文書中包的版本:commons-fileupload-1.2.1.jar、struts2-core-2.1.2.jar

          孫鑫的書《Struts2 深入詳解》509頁是關于限制上傳文件的最大長度的內容。
          其中談到fileUpload攔截器只是當文件上傳到服務器上之后,才進行的文件類型和大小判斷。
          Struts2框架底層默認用的是apache的commons-fileupload組件對上傳文件進行接受處理。
          通過struts.multipart.maxSize屬性來對文件大小進行限定時,將直接影響到commons-fileupload組件的文件大小設定,默認是2M。當上傳文件超過了這個尺寸時,將從commons-fileupload組件中拋出SizeLimitExceededException異常。上傳文件攔截器捕獲到這個異常后,將直接把該異常信息設置為Action級別的錯誤信息。

          經過我的測試和對源代碼的Debug,發現確實如孫鑫書中所言,如果上傳文件大于2M時,在頁面上就出現了一堆英文的錯誤信息,大致是:the request was rejected because its size....exceeds the configured maximum...并且在fieUpload中將來自MultiPartRequestWrapper型request對象的錯誤信息給加到了Action的錯誤中。

          這時候,你在ApplicationResources.properties中自定義的上傳文件過大的錯誤信息根本不起作用。原因就如書上所言,在底層commons-fileupload組件中就把異常給拋出來了文件根本沒被上傳,所以到了fileUpload攔截器時,根據取不到文件,當然也就沒法對文件的類型和大小進行判斷了。

          然而,這個異常直接帶來兩個問題:

          1、在頁面上顯示了英文的錯誤信息。這樣的信息顯然不是我們想要的。
          2、由于錯誤的產生,原來頁面上輸入的其他文本內容也都不見了,也就是說params注入失敗。


          帶著這兩個問題,我們來探尋一下Struts2對于請求的處理過程。
          注:這并不是一篇關于Struts2請求過程的介紹,主要是為了解決以上兩個問題,才引起的簡單分析。

          首先當然我們要拿FilterDispatcher開刀。

          在doFilter方法中調用了prepareDispatcherAndWrapRequest方法,為了包裝出Struts2自己的request對象,在prepareDispatcherAndWrapRequest方法中調用Dispatcher類的wrapRequest方法,在這個方法里,會根據請求內容的類型(提交的是文本的,還是multipart/form-data格式),決定是使用tomcat的HttpServletRequestWrapper類分離出請求中的數據,還是使用Struts2的MultiPartRequestWrapper來分離請求中的數據。
          注:向服務器請求時,數據是以流的形式向服務器提交,內容是一些有規則東東,我們平時在jsp中用request內置對象取parameter時,實際上是由tomcat的HttpServletRequestWrapper類分解好了的,無需我們再分解這些東西了。

          當然,在這里,我們研究的是上傳文件的情況,所以,由于form中設定的提交內容是媒體格式的,所以,Dispatcher類的wrapRequest方法會將請求交由MultiPartRequestWrapper類來處理。

          MultiPartRequestWrapper這個類是Struts2的類,并且繼承了tomcat的HttpServletRequestWrapper類,也是我們將用來代替HttpServletRequest這個類的類,看名字也知道,是對多媒體請求的包裝類。
          Struts2本身當然不會再造個輪子,來解析請求,而是交由Apache的commons-fileupload組件來解析了。
          在MultiPartRequestWrapper的構造方法中,會調用MultiPartRequest(默認為JakartaMultiPartRequest類)的parse方法來解析請求。

          在Struts2的JakartaMultiPartRequest類的parse方法中才會真正來調用commons-fileupload組件的ServletFileUpload類對請求進行解析,至此,Struts2已經實現了將請求轉交commons-fileupload組件對請求解析的全過程。剩下的就是等commons-fileupload組件對請求解析完畢后,拿到分解后的數據,根據field名,依次將分解后的field名和值放到params(HashMap類型)里,同時JakartaMultiPartRequest類重置了HttpServletRequest的好多方法,比如熟知的getParameter、getParameterNames、getParameterValues,實際上都是從解析后得到的那個params對象里拿數據,在這個過程,commons-fileupload組件也乖乖的把上傳的文件分析好了,JakartaMultiPartRequest也毫不客氣的把分解后的文件一個一個的放到了files(HashMap類型)中,實際上此時,commons-fileupload組件已經所有要上傳的文件上傳完了。至此,Struts2實現了對HttpServletRequest類的包裝,當回到MultiPartRequestWrapper類后,再取一下上述解析過程中發生的錯誤,然后把錯誤加到了自己的errors列表中了。同樣我們會發現在MultiPartRequestWrapper類中,也把HttpServletRequest類的好多方法重載了,畢竟是個包裝類嘛,實際上對于上傳文件的請求,在Struts2后期的處理中用到的request都是MultiPartRequestWrapper類對象,比如我們調用getParameter時,直接調用的是MultiPartRequestWrapper的getParameter方法,間接調的是JakartaMultiPartRequest類對象的getParameter方法。
          注:從這里,我們就可以看出,JakartaMultiPartRequest是完全設計成可以替換的類了。

          然后繼續向回返,到了Dispatcher類的wrapRequest方法,直接把MultiPartRequestWrapper對象返回了,我們就終于回到了FilterDispatcher類的prepareDispatcherAndWrapRequest方法,此時,我們拿到了完全解析好了的request對象(MultiPartRequestWrapper類),該對象又進一步被返回到了FilterDispatcher類的doFilter方法,也就是回到了出發點,至此,doFilter中拿到的request對象就是一個將請求中的數據分解好的了HttpServletRequest對象,我們完全可以用getParameter方法取其中的數據了,同時,我們也可以用getFiles得到文件數組了。
          doFilter方法中,會進一步調用actionMapper的getMapping方法對url進行解析,找出命名空間和action名等,以備后面根據配置文件調用相應的攔截器和action使用。

          關于doFilter方法中下一步對Dispatcher類的serviceAction方法的調用,不再描述,總之在action被調用之前,會首先走到fileUpload攔截器(對應的是FileUploadInterceptor類),在這個攔截器中,會先看一下request是不是 MultiPartRequestWrapper,如果不是,就說明不是上傳文件用的request,fildUpload攔截器會直接將控制權交給下一個攔截器;如果是,就會把request對象強轉為MultiPartRequestWrapper對象,然后調用hasErrors方法,看看有沒有上傳時候產生的錯誤,有的話,就直接加到了Action的錯誤(Action級別的)中了。另外,在fileUpload攔截器中會將MultiPartRequestWrapper對象中放置的文件全取出來,把文件、文件名、文件類型取出來,放到request的parameters中,這樣到了params攔截器時,就可以輕松的將這些內容注入到Action中了,這也就是為什么fileUpload攔截器需要放在params攔截器前面的理由。在文件都放到request的parameters對象里之后,fileUpload攔截器會繼續調用其他攔截器直到Action等執行完畢,他還要做一個掃尾的工作:把臨時文件夾中的文件刪除(這些文件是由commons-fileupload組件上傳的,供你在自己的Action中將文件copy到指定的目錄下,當action執行完了后,這些臨時文件當然就沒用了)。

          你好,你還在看嗎?呵呵,是不是太多了,也太亂了,沒辦法,Struts2就是這樣的調用的。也不知道Struts2有沒有公開其Sequence圖,我是想畫一個,不過,太懶,還是看著代碼說說吧。

          如果上面看煩了,也完全可以不看了,直接看下面的。

          在上面一番分析之后,文件上傳的全過程就結束了。
          我們回到我們的問題上來。

          先看第一個:
          1、在頁面上顯示了英文的錯誤信息。這顯然不是我們想要的。

          沒辦法了,commons-fileupload組件沒想到國際化,在FileUploadInterceptor攔載器中,也沒想著國際化,直接放到Action的錯誤中了,就沒他事了,三種做法:
            (1)在錯誤顯示之前,把這條錯誤給換掉,應該難度不大,我沒做留給你做了。
            (2)或者重寫一下JakartaMultiPartRequest這個類,把捕捉到的異常信息換成自己的,然后,通過Struts2的配置文件,把我們重寫的這個parser換上去用。
            (3)直接改commons-fileupload組件的類,換成中文的。
          我具體說一下第(3)種做法:找到FileUploadBase類,把902行~908行改一下。
          FileUploadException ex =
              new SizeLimitExceededException(
                  "the request was rejected because"
                  + " its size (" + pCount
                  + ") exceeds the configured maximum"
                  + " (" + pSizeMax + ")",
                  pCount, pSizeMax);
          =>
          FileUploadException ex = new SizeLimitExceededException(
          "服務器拒絕了您的請求,原因可能是向服務器提交的數據發生了丟失。", pCount, pSizeMax);

          把914行~918行改一下。
          throw new SizeLimitExceededException(
                  "the request was rejected because its size ("
                  + requestSize
                  + ") exceeds the configured maximum ("
                  + sizeMax + ")",
          =>
          throw new SizeLimitExceededException("服務器拒絕了您的請求,原因是提交數據量過大(通常是由于上傳文件過大),請返回上頁重試。"
          + " (最大字節數:" + sizeMax / 1024
          + "K)", requestSize, sizeMax);


          再看一下第二個問題。
          2、由于錯誤的產生,原來頁面上輸入的內容也全部不見了,也就是說params注入失敗。
          關于這個問題我在javaeye上搜索到一篇文章(使用的commons-fileupload組件的jar包似乎比較老)。
          http://www.javaeye.com/topic/197345

          雖然按照此文,當上傳失敗時,能夠將其他輸入內容顯示出來,但是這樣做的結果是全部的文件肯定會上傳到服務器上,也就是說,雖然是頁面上報了文件因為太大,請求被拒絕的錯,但是文件依然會被上傳到服務器上,commons-fileupload組件根本沒會去攔文件的上傳。
          在這里要說明一下,如果你不拋出這個異常,請求的流會繼續向服務器上傳,只有當整個流上傳完了之后,commons-fileupload組件才能正確的分析出文件部分、文本部分。所以,在這里拋出異常是不得已的作法,如果不拋異常,后果是雖然頁面報錯,但文件還是會被傳到服務器的上,這一步根本沒擋住輸入流的上傳,如果沒擋住的話,大家想想會有什么后果?
          所以,綜上所述,對于第二個問題,如果出現了這個異常,我們根本無法讓原來輸入的內容還顯示出來的,因為commons-fileupload組件并沒有解析全部的輸入內容,直接給出異常了,到了params攔截器中,request里就是空的,根本取不到parameter,所以也就無法注入到Action中了。這種情況下,只能顯示一個告知用戶由于提交數據量過大,服務器拒絕了請求的錯誤信息,比較好的方法是,直接跳到一個專門的頁面,提示用戶,然后讓用戶點返回來再次輸入,否則用戶會感覺上傳文件大就大吧,怎么連我輸入的其他一些內容也沒給保存住。當然,如果能用Ajax來上傳文件,對客戶的操作體驗可能是最好的,但是,這樣可能會導致服務器上有些掛空的文件(上傳后從來沒被用過),需要想法清除的。

          整個分析下來,我們說第二個問題基本上是無法避免的。
          posted @ 2009-04-14 12:46 lanxin1020 閱讀(374) | 評論 (0)編輯 收藏
               摘要: Web Service概述 Web Service的定義 W3C組織對其的定義如下,它是一個軟件系統,為了支持跨網絡的機器間相互操作交互而設計。Web Service服務通常被定義為一組模塊化的API,它們可以通過網絡進行調用,來執行遠程系統的請求服務。 這里我們從一個程序員的視角來觀察web service。在傳統的程序編碼中,存在這各種的函數方法調用。通常,我們知道一個程序...  閱讀全文
          posted @ 2009-04-13 18:37 lanxin1020 閱讀(238) | 評論 (0)編輯 收藏
          技術要點
          本節代碼詳細說明文件上傳功能的開發流程,介紹知識點如下:
          ? 文件上傳頁面和顯示上傳成功頁面代碼內容。
          ? UploadAction類中實現上傳功能方法和上傳文件屬性介紹。
          ? struts.xml中UploadAction配置,以及字符編碼、文件臨時存放路徑配置。
          ? 上傳后所處路徑和最終上傳成功后效果展示。

          演示代碼
          上傳文件頁面,這里筆者定義的是多個文件上傳。
          Java代碼
          1. <!---------------------文件名:upload.jsp----------------->   
          2. <%@taglib prefix="s" uri="/struts-tags"%>   
          3. <html>   
          4.     <head>   
          5.         <meta http-equiv="Content-Type" content="text/html; charset=gb2312">   
          6.         <title>上傳文件</title>   
          7.     </head>   
          8.     <body>   
          9.     <!-- 上傳文件表單定義 -->   
          10.     <s:form action="upload" method="post" enctype="multipart/form-data">   
          11.         <tr>   
          12.     <!-- 上傳文件標簽定義 -->   
          13.     <td>上傳文件:<s:file name="file"></s:file></td>   
          14.     </tr>   
          15.     <tr>   
          16.     <td>再次上傳文件:<s:file name="file"></s:file></td>   
          17.     </tr>   
          18.     <tr>   
          19.     <td align="left"><s:submit name="submit" value="提交"></s:submit></td>   
          20.     </tr>   
          21.     </s:form>   
          22.     </body>   
          23. </html>  

          上傳文件成功后結果頁面
          Java代碼
          1. <!-------------------文件名:result.jsp ----------------->   
          2. <%@taglib prefix="s" uri="/struts-tags"%>   
          3. <html>   
          4.     <head>   
          5.         <meta http-equiv="Content-Type" content="text/html; charset=gb2312">   
          6.         <title>上傳結果</title>   
          7.     </head>   
          8.     <body>   
          9.         上傳文件:   
          10.         <!-- 顯示上傳成功文件名 -->   
          11.         <s:property value="fileFileName" />   
          12.     </body>   
          13. </html>  

          UploadAction類代碼
          Java代碼
          1. <!------------------文件名:UploadAction.java ------------------>   
          2. import java.io.File;   
          3. import java.io.FileInputStream;   
          4. import java.io.FileNotFoundException;   
          5. import java.io.FileOutputStream;   
          6. import java.io.IOException;   
          7. import java.io.InputStream;   
          8. import java.io.OutputStream;   
          9. import java.util.List;   
          10.   
          11. import org.apache.struts2.ServletActionContext;   
          12. import com.opensymphony.xwork2.ActionSupport;   
          13.   
          14. //文件上傳Action   
          15. public class UploadAction extends ActionSupport {   
          16.     //上傳文件存放路徑   
          17.     private final static String UPLOADDIR = "/upload";   
          18.     //上傳文件集合   
          19.     private List<File> file;   
          20.     //上傳文件名集合   
          21.     private List<String> fileFileName;   
          22.     //上傳文件內容類型集合   
          23.     private List<String> fileContentType;   
          24.   
          25.     public List<File> getFile() {   
          26.         return file;   
          27.     }   
          28.   
          29.     public void setFile(List<File> file) {   
          30.         this.file = file;   
          31.     }   
          32.   
          33.     public List<String> getFileFileName() {   
          34.         return fileFileName;   
          35.     }   
          36.   
          37.     public void setFileFileName(List<String> fileFileName) {   
          38.         this.fileFileName = fileFileName;   
          39.     }   
          40.   
          41.     public List<String> getFileContentType() {   
          42.         return fileContentType;   
          43.     }   
          44.   
          45.     public void setFileContentType(List<String> fileContentType) {   
          46.         this.fileContentType = fileContentType;   
          47.     }   
          48.   
          49.     public String execute() throws Exception {   
          50.         for (int i = 0; i < file.size(); i++) {   
          51.             //循環上傳每個文件   
          52.             uploadFile(i);   
          53.         }   
          54.         return "success";   
          55.     }   
          56.   
          57.     //執行上傳功能   
          58.     private void uploadFile(int i) throws FileNotFoundException, IOException {   
          59.         try {   
          60.             InputStream in = new FileInputStream(file.get(i));   
          61.             String dir = ServletActionContext.getRequest().getRealPath(UPLOADDIR);   
          62.             File uploadFile = new File(dir, this.getFileFileName().get(i));   
          63.             OutputStream out = new FileOutputStream(uploadFile);   
          64.             byte[] buffer = new byte[1024 * 1024];   
          65.             int length;   
          66.             while ((length = in.read(buffer)) > 0) {   
          67.                 out.write(buffer, 0, length);   
          68.             }   
          69.   
          70.             in.close();   
          71.             out.close();   
          72.         } catch (FileNotFoundException ex) {   
          73.             ex.printStackTrace();   
          74.         } catch (IOException ex) {   
          75.             ex.printStackTrace();   
          76.         }   
          77.     }   
          78. }  

          struts.xml配置文件中有關文件上傳的配置:
          Java代碼
          1. <!--------------------文件名:struts.xml------------------->   
          2. <struts>   
          3.     <!-- 系統常量定義,定義上傳文件字符集編碼 -->   
          4.     <constant name="struts.i18n.encoding" value="gb2312"></constant>   
          5.     <!-- 系統常量定義,定義上傳文件臨時存放路徑 -->   
          6.     <constant name="struts.multipart.saveDir" value="c:\"></constant>   
          7.     <!-- Action所在包定義 -->   
          8.     <package name="C04.4" extends="struts-default">   
          9.         <!-- Action名字,類以及導航頁面定義 -->   
          10.         <!-- 通過Action類處理才導航的的Action定義 -->   
          11.         <action name="upload" class="action.UploadAction">   
          12.             <result name="input">/jsp/upload.jsp</result>   
          13.             <result name="success">/jsp/result.jsp</result>   
          14.         </action>   
          15.     </package>   
          16. </struts>   

          (1):文件上傳頁面如圖4.8所示。

          圖4.8  文件上傳
          (2):選擇文件如圖4.9所示。

          圖4.9  選擇上傳的文件
          (3):單擊“提交”按鈕后文件上傳成功頁面,并顯示上傳文件名,如圖4.10所示。

          圖4.10  上傳文件成功后效果
          (4):兩個被上傳文件最終在服務器上存放路徑效果如圖4.11所示。

          圖4.11  上傳文件存放路徑圖
          代碼解釋
          (1)在upload.jsp中通過Form標簽和File標簽定義了兩個上傳文件。Struts2標簽筆者會在之后章節里具體介紹,這里只是讓讀者知道是如何使用標簽顯示圖4.8顯示的內容。如果上傳成功,筆者在result.jsp中“[”和“]”之間顯示上傳文件的文件名,如果是多個文件,以“,”相隔。這些顯示格式都是用Property標簽定義的。
          注意:如果上傳文件,在JSP的Form中一定要定義如upload.jsp文件中黑體表示的部分。method和enctype屬性都必須要如代碼中所示。這樣Form中上傳文件才會起作用。
          (2)UploadAction文件中先定義了常量UPLOADDIR,它是上傳文件上傳后存放的文件夾名字。比如筆者使用的是JBoss(附錄中有安裝和在MyEclipse中部署的操作說明),則在它的已部署Web項目下的upload文件夾中,會有所有上傳成功的文件。如圖4.11讀者也可以看見它的上傳文件最終存放路徑。
          注意:在MyEclipse中開發的“WebRoot”目錄下也要新建一個upload文件夾,否則部署后在JBoss的已部署Web項目下將沒有upload文件夾。因為部署的時候會將所有“WebRoot”目錄下的文件夾和文件都部署到JBoss的已部署Web項目下。
          定義好UPLOADDIR后,在定義上傳文件的屬性變量。也許其中的“fileFileName”和“fileContentType”讀者看了有點別扭,尤其是“fileFileName”感覺不符合Java命名規范,但是這兩個屬性變量是4.1小節中介紹的“fileUpload”攔截器類中的類公有變量名字,只有這樣定義,UploadAction執行時候會把在頁面上選擇的上傳文件的屬性值放在這兩個變量里面,否則調試UploadAction時候會發現這兩個變量都會是“null”即空值。不相信的讀者可以自行改變這兩個變量名再執行上傳文件功能進行調試看一下這兩個變量得到的值。
          注意:因為這里筆者是進行多個文件上傳功能開發,因此“file”、“fileFileName”、“fileFileName”屬性變量都設定為List類型,其實還可以設定為數組類型。個人覺得沒有啥大區別。完全憑個人喜好而定。還有如果讀者自己開發單個文件上傳,就沒必要把它們設定為List類型或數組類型。直接把“file”定義為Java的IO包中的File類型,“fileFileName”、“fileFileName”定義為普通的String類型即字符串類型。
          之后在execute方法中,寫一個循環,對所有頁面中選擇的上傳文件一個個進行上傳。這里筆者運用了重構中的“抽取方法”的方式,將上傳文件的功能封裝成一個私有方法,名字為“uploadFile”。其中運用了Java的IO包中很多API方法。有對重構和Java的IO功能不了解的讀者可以去查閱相關資料去理解掌握,這里不是本書以及本節重點,因此不再具體記述。
          (3)struts.xml中定義了<constant>標簽,主要定義了文件名和文件內容顯示的字符編碼集以及這些被上傳文件臨時存放路徑。
          先說明一下<constant>標簽,顧名思義這是定義整個Web項目的一些常量屬性值,如果不定義則在Struts2自帶的default.properties(讀者們可到自己安裝Struts2的文件路徑src\core\src\main\resources\org\apache\struts2\下找到)文件中有這些常量的定義,比如在本節struts.xml文件中的“struts.i18n.encoding”和“struts.multipart.saveDir”在default.properties定義代碼如下:
          Java代碼
          1. <!--------------------文件名:default.properties---------------->   
          2. ### This can be used to set your default locale and encoding scheme   
          3. # struts.locale=en_US   
          4. struts.i18n.encoding=UTF-8  
          5.   
          6. ### Parser to handle HTTP POST requests, encoded using the MIME-type multipart/form-data   
          7. # struts.multipart.parser=cos   
          8. # struts.multipart.parser=pell   
          9. struts.multipart.parser=jakarta   
          10. # uses javax.servlet.context.tempdir by default  
          11. struts.multipart.saveDir=  

          如果不在struts.xml文件中定義,則Web項目會缺省使用default.properties文件中這兩個常量屬性的定義。一個將使字符編碼集變為“UTF-8”,另一個干脆沒有任何文件路徑指定。而筆者開發的該Web項目缺省支持的字符編碼集是“gb2312”,而且需要指定臨時上傳文件存放路徑。(當然如果讀者開發的Web項目缺省編碼集就是“UTF-8”,而且也并不需要指定臨時路徑時候,就沒必要在struts.xml中定義這兩個<constant>),因此有必要定義這兩個屬性符合項目開發要求。
          注意:也可以如第3章那樣,把這兩個屬性定義在自定義的struts.properties文件中,具體代碼可以如下:
          Java代碼
          1. <!------------------------文件名:struts.properties------------------>   
          2. struts.i18n.encoding =gb2312   
          3. struts.multipart.saveDir= c:\  

          筆者個人認為比在struts.xml中定義更加好,畢竟Struts2自己也是定義在properties屬性文件中,而不是定義在自己的xml配置文件中。(Struts2自帶的xml配置文件為struts-default.xml,在4.1小節中已記述)。這里是為了讓讀者知道struts.xml配置文件也可以配置這些屬性,因此寫在struts.xml配置文件中。從3.2小節筆者說明struts.xml配置文件時并沒有介紹<constant>標簽這點也可以知道筆者個人其實是不贊同這樣的配置手段即在struts.xml中配置<constant>標簽。
          在<Action>標簽中配置“result”,和第3章類似,將這兩個JSP文件的導航流程配置好即可。
          (4)開始進行文件上傳功能展示,按照如上記述的步驟執行即可。筆者在桌面上新建了兩個文本文件,將它們上傳到JBoss已部署的Web項目中展示文件上傳的upload文件夾下。如圖4.11所示。
          其實還可以指定上傳文件的格式,讓它只上傳特定類型的文件。比如只能上傳文本和xml文件,則在struts.xml需要顯示配置“uploadFile”攔截器。如下代碼:
          Java代碼
          1. <!-----------------------文件名:struts.xml------------------>   
          2. <struts>   
          3.     <!-- Action所在包定義 -->   
          4.     <package name="C04.4" extends="struts-default">   
          5.         <!-- Action名字,類以及導航頁面定義 -->   
          6.         <!-- 通過Action類處理才導航的的Action定義 -->   
          7.         <action name="upload" class="action.UploadAction">   
          8.             <result name="input">/jsp/upload.jsp</result>   
          9.             <result name="success">/jsp/result.jsp</result>   
          10.         </action>   
          11. <!—顯示配置文件上傳攔截器 -->   
          12. <interceptor-ref name=”fileUpload”>   
          13. <!—指定特定類型的上傳文件 -->   
          14. <param name =”allowedTypes”>text/plain,application/xml</param>   
          15. </ interceptor-ref >   
          16. <interceptor-ref name=”defaultStack”></ interceptor-ref >   
          17.     </package>   
          18. </struts>   

          定義了一個名為“allowedTypes”的參數,其中在<param></param>之間的是文件類型,也可以用“,”間隔,表示允許上傳多個文件類型。這里允許上傳文件類型為txt、xml格式的文件。如果讀者不知道各個文件類型的定義,可在自己的JBoss安裝目錄中的server\default\deploy\jboss-web.deployer\conf\下的web.xml文件中找到(搜索<mime-mapping>即可)。
          注意:如果顯示配置Struts2自己的缺省攔截器一定要寫在“defaultStack”前,否則“fileUpload”攔截器不會執行攔截。因為Struts2中如果某個攔截器執行攔截時候發現自己已經執行過,第二個乃至之后同名的攔截器都不會執行。這里因為“defaultStack”攔截器棧中包含了“fileUpload”攔截器,而“fileUpload”攔截器已經執行攔截了,則不會再執行攔截。如果把“defaultStack”攔截器棧放在“fileUpload”攔截器前配置,則只執行“defaultStack”攔截器棧中的“fileUpload”攔截器,這里是沒有定義“allowedTypes”的,Struts2缺省默認的是支持所有文件類型。因此它會支持所有文件類型的文件上傳。因此再設定“allowedTypes”就沒有任何意義了。
          posted @ 2009-04-13 15:33 lanxin1020 閱讀(234) | 評論 (0)編輯 收藏
          Struts2文件下載功能開發
          技術要點
          本節代碼詳細說明文件下載功能的開發流程,介紹知識點如下:
          ? 上傳成功頁面重修改后支持文件下載代碼內容。
          ? DownloadAction文件下載功能開發。
          ? struts.xml中DownloadAction配置,以及支持文件名為中文字符的文件下載。
          ? 下載文件流程展示。

          演示代碼
          上傳成功頁面,這里筆者讓其在每個上傳文件后提供“下載”鏈接。
          Java代碼
          1. <!------------------------文件名:result.jsp------------------->   
          2. <%@taglib prefix="s" uri="/struts-tags"%>   
          3.     <body>   
          4.         上傳文件:   
          5.         <table>   
          6.         <!-- 循環顯示上傳成功文件名 -->   
          7.         <s:iterator value="fileFileName" status="fn">   
          8.         <tr>   
          9.         <td>   
          10.         <!-- 上傳成功文件名 -->   
          11.         <s:property />           
          12.         </td>   
          13.         <td>   
          14.         <!-- 下載文件鏈接內容為定義的下載Action -->   
          15.         <!-- 下載文件名作為鏈接參數fileName值,用OGNL表達式表達 -->     
          16.         <a href="<s:url value='download.action'>                  
          17.                     <s:param name='fileName'  
          18.  value='fileFileName[#fn.getIndex()]'/>     
          19.                  </s:url>">下載</a>   
          20.         </td>   
          21.         </tr>   
          22.         </s:iterator>        
          23.         </table>         
          24.     </body>  

          DownLoadAction類代碼
          Java代碼
          1. <!------------文件名:DownLoadAction.java ------------------>   
          2. import java.io.InputStream;   
          3. import java.io.UnsupportedEncodingException;   
          4.   
          5. import org.apache.struts2.ServletActionContext;   
          6. import com.opensymphony.xwork2.ActionSupport;   
          7.   
          8. public class DownLoadAction extends ActionSupport {   
          9.     //下載文件原始存放路徑   
          10.     private final static String DOWNLOADFILEPATH="/upload/";   
          11.     //文件名參數變量   
          12.     private String fileName;   
          13.   
          14.     public String getFileName() {   
          15.         return fileName;   
          16.     }   
          17.   
          18.     public void setFileName(String fileName) {   
          19.         this.fileName = fileName;   
          20.     }   
          21.   
          22.     //從下載文件原始存放路徑讀取得到文件輸出流   
          23.     public InputStream getDownloadFile() {   
          24.         return    
          25. ServletActionContext.getServletContext().getResourceAsStream(DOWNLOADFILEPATH+fileName);   
          26.     }   
          27.     //如果下載文件名為中文,進行字符編碼轉換   
          28.     public String getDownloadChineseFileName() {   
          29.         String downloadChineseFileName = fileName;   
          30.   
          31.         try {   
          32.             downloadChineseFileName = new String(downloadChineseFileName.getBytes(), "ISO8859-1");   
          33.         } catch (UnsupportedEncodingException e) {   
          34.             e.printStackTrace();   
          35.         }   
          36.   
          37.         return downloadChineseFileName;   
          38.     }   
          39.   
          40.     public String execute() {   
          41.         return SUCCESS;   
          42.     }   
          43. }  

          struts.xml配置文件中有關文件下載的配置:
          Java代碼
          1. <!------------------文件名:struts.xml----------------->   
          2. <struts>   
          3.     <!-- 下載文件的Action定義 -->   
          4.         <action name="download" class="action.DownLoadAction">   
          5.             <!-- 設置文件名參數,由頁面上傳入 -->   
          6.             <param name="fileName"></param>   
          7.             <result name="success" type="stream">   
          8.                 <!-- 下載文件類型定義 -->   
          9.                 <param name="contentType">text/plain</param>   
          10.                 <!-- 下載文件處理方法 -->   
          11.                 <param name="contentDisposition">   
          12.                     attachment;filename="${downloadChineseFileName}"  
          13.                 </param>   
          14.                 <!-- 下載文件輸出流定義 -->   
          15.                 <param name="inputName">downloadFile</param>   
          16.             </result>   
          17.         </action>   
          18. </struts>   

          (1):文件開始下載頁面如圖4.12所示。

          圖4.12  文件下載
          (2):單擊“下載”鏈接,比如點“下載文件1.txt”文件右邊“下載”鏈接,出現對話框如圖4.13所示。

          圖4.13  下載文件處理方式
          (3):單擊“保存”按鈕后選擇下載文件存放路徑,如圖4.14所示。

          圖4.14  下載文件選擇存放路徑
          代碼解釋
          (1)在result.jsp中通過iterator標簽和url標簽定義了“fileFileName”的循環顯示以及鏈接。其中有關“status”和OGNL表達式筆者會在之后章節里具體介紹,這里只是讓讀者知道是如何使用標簽顯示圖4.12顯示的內容。特別指出<param>標簽為downloadAction定義了一個參數,該參數名為“fileName”,因為在4.4.1小節中筆者定義的“fileFileName”是個List類型的數據集合,因此利用OGNL表達式將文件名作為“fileName”參數值傳入downloadAction中。
          (2)DownLoadAction文件中先定義了常量DOWNLOADFILEPATH,它是下載文件在服務器存放的路徑名,也就是4.4.1小節中上傳文件在服務器存放的路徑名。
          定義好DOWNLOADFILEPATH后,在定義DownLoadAction的屬性變量。因為在result.jsp中定義了參數“fileName”,則它作為DownLoadAction的屬性變量,需要定義相應的getter、setter方法。
          然后定義了getDownloadFile方法,它返回的是一個文件流,表明將被下載文件轉換為輸出流,方便下載。利用Struts2自帶的“ServletActionContext”類的API把下載文件存放路徑作為方法參數,讀取下載文件,將其轉換為文件流。
          還有一個getDownloadChineseFileName方法,該方法主要作用是將文件名為中文字符的文件進行文件名的字符編碼集合轉換。因為在Web系統中由JSP等視圖頁面傳入的變量值,特別是中文字符的變量。缺省的字符編碼集合都是“ISO8859-1”,因此利用Java的字符串類的API,將字符編碼轉成開發需要的字符編碼集。防止中文字符亂碼問題發生。
          (3)struts.xml中定義了名為“download”的Action。其中它自己的參數“fileName”因為在這里它的值會從JSP頁面上傳入,所以這里只是定義,沒有具體給它賦任何值
          在<result>標簽中定義了type屬性,值為“stream”。如果是下載文件功能開發,DownLoadAction一定要設置type屬性,而且值為“stream”。這是因為在Struts2自帶的xml配置文件為struts-default.xml中有關于“stream”的result返回類型的定義,代碼如下:
          Java代碼
          1. <!-------------------文件名:struts-default.xml-------------->   
          2. <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>  

          這里Struts2定義了result返回類型為“stream”,這個result類型主要是處理文件的輸入和輸出流時候需要使用的。因為下載文件就是把文件轉換成輸入輸出流,將其從一個文件路徑放到另外一個文件路徑中去。所以肯定要設置這個result類型的。
          “contentType”、“contentDisposition”、“inputName”都是這個result的屬性。“contentType”就是文件類型。這里因為下載的文件是文本文件,因此設定的值為文本文件類型,具體各個文件類型如何定義,4.4.1小節已經介紹過,這里不再做說明。“contentDisposition”是指定下載文件處理方式,如圖4.13就是處理方式的效果。特別指出如果“contentDisposition”定義的值把前面的“attachment”去掉,則下載方式不是以附件方式下載,如果單擊“下載”鏈接,則會把下載文件的內容顯示在瀏覽器中。讀者可以去試驗一下。這里有個“${downloadChineseFileName}”,這就是在DownLoadAction中定義getDownloadChineseFileName方法的目的,${downloadChineseFileName}是OGNL的表達式,它顯示了“downloadChineseFileName”變量的具體值,因為在DownLoadAction中定義getDownloadChineseFileName方法,則把已經轉換成符合需要字符編碼集的下載文件名作為下載文件方式對話框中顯示的名稱,不會造成任何亂碼問題。“inputName”是最關鍵的一個屬性,也是一定要定義的屬性,“inputName”參數中定義的值“downloadFile”就是DownLoadAction中getDownloadFile方法返回的文件流名字。在Struts2中Acion用前綴名為get的方法得到各種屬性的值,這些屬性有些是在Action中定義,有些就像本示例在配置文件中利用OGNL表達式或直接定義。
          (4)開始進行文件下載功能展示,按照如上記述的步驟執行即可。筆者將兩個文本文件上傳上去,然后在上傳成功頁面對具體的文件進行下載。在圖4.13中單擊“保存”按鈕就顯示圖4.14,選擇在本機上存放下載文件的路徑即可完成下載文件功能。
          posted @ 2009-04-13 15:30 lanxin1020 閱讀(769) | 評論 (0)編輯 收藏
          Struts2標簽使用原理解疑
          在筆者下載的Struts2的包中,讀者可以在/lib下找到struts2-core-2.0.11.1.jar包,解壓該包在其根目錄下的/META-INF文件夾下可以看到一個名字為“struts-tags.tld”文件。該文件就是Struts2中所有自帶的標簽庫定義。本節通過對該文件代碼的介紹來讓讀者知曉Struts2內部是如何使用這些標簽來進行工作。并簡單說明JSP中是如何用其來書寫標簽代碼。
          技術要點
          本節代碼說明Struts2內部定義標簽的格式和在JSP中使用方式。
          ? struts-tags.tld文件定標簽定義配置格式。
          ? JSP中使用標簽功能介紹。

          演示代碼
          Java代碼
          1. <!------------------文件名: struts-tags.tld----------------->   
          2. <taglib>   
          3.   <tlib-version>2.2.3</tlib-version>   
          4.   <jsp-version>1.2</jsp-version>   
          5.   <short-name>s</short-name>   
          6.   <uri>/struts-tags</uri>   
          7.   <display-name>"Struts Tags"</display-name>   
          8.   <description>………………</description>   
          9.   <tag>   
          10.     <name>action</name>   
          11.     <tag-class>org.apache.struts2.views.jsp.ActionTag</tag-class>   
          12.     <body-content>JSP</body-content>   
          13.     <description><![CDATA[Execute an action from within a view]]></description>   
          14.     <attribute>   
          15.       <name>executeResult</name>   
          16.       <required>false</required>   
          17.       <rtexprvalue>false</rtexprvalue>   
          18.       <description><![CDATA[Whether the result of this action (probably a view) should be executed/rendered]]></description>   
          19.     </attribute>   
          20.    …………………………   
          21.     <attribute>   
          22.       <name>namespace</name>   
          23.       <required>false</required>   
          24.       <rtexprvalue>false</rtexprvalue>   
          25.       <description><![CDATA[Namespace for action to call]]></description>   
          26.     </attribute>   
          27.   </tag>   
          28. </taglib>  

          代碼解釋
          (1)struts-tags.tld是Struts2自標簽定義文件。所有標簽定義都是在<tablib>和</taglib>之間定義。以<tag></tag>用來定義一個具體標簽。每個標簽因為都可以有很多自己的屬性。這些屬性定義都是以<attribute></attribute>來定義。
          (2)<tlib-version></tlib-version>之間定義的是標簽庫的版本。<jsp-version></jsp-version>定義的是標簽庫這些標簽是支持JSP的哪個版本。<short-name> </short-name>其實是標簽庫的默認名,也可以認為是其昵稱。<uri> </uri>定義的是標簽庫的URI,在JSP中會使用到。<display-name></display-name>是顯示名。<description></description>是標簽庫的記述,記述標簽庫的使用用途等等。
          (3)<attribute>中<name></name>是屬性名稱定義。<required></required>表示的該屬性是否是必須的屬性,如果是必須的則<required></required>之間為true,否則為false。<rtexprvalue></rtexprvalue>表示的是可否使用表達式,大多數標簽都是為false。這里不是不能使用表達式,而是恰恰相反表示可以使用表達式。<description></description>定義和前面介紹相同。
          (4)在JSP中,如之前章節的演示代碼所示,都是在文件頭有個使用標簽的聲明,代碼如下。
          Java代碼
          1. <!---------------------文件名: *.jsp------------------------->   
          2. <%@taglib prefix="s" uri="/struts-tags"%>  

          有了這個聲明,在JSP文件中就可以使用Struts2的標簽。比如form標簽定義要像如下代碼所示。
          Java代碼
          1. <s:form action="upload" ………>  

          記住一定要用“s”,它是Struts2中標簽的默認名也是相當于一個昵稱,當然讀者也可以把它改為自己想取的名字,不過在標簽聲明中的“prefix”中就要改成那個自己取的名字。
          注意:因為筆者使用的Servlet版本是2.3之上的版本,因此沒必要在web.xml中定義標簽庫。如果讀者使用的Servlet版本比較低,則在web.xml文件中需要定義如下的代碼:
          Java代碼
          1. <!----------------------文件名:web.xml----------------------->   
          2. <taglib>   
          3.     <!- 定義URI - ->   
          4.     <taglib-uri>/Struts 2-tags</taglib-uri>   
          5. <!- 定義標簽庫支持的jar包位置- ->   
          6.     <taglib-location>/WEB-INF/lib/struts2-core-2.0.11.1.jar</taglib-location>   
          7. </taglib>  

          只有這樣標簽庫才會在Servlet版本比較低的情況下使用有效果。
          posted @ 2009-04-13 15:28 lanxin1020 閱讀(465) | 評論 (0)編輯 收藏
          --sql structured query language

          --DML--Data Manipulation Language--數據操作語言

          query information (SELECT),
          add new rows (INSERT),
          modify existing rows (UPDATE),
          delete existing rows (DELETE),
          perform a conditional update or insert operation (MERGE),
          see an execution plan of SQL (EXPLAIN PLAN),
          and lock a table to restrict access (LOCK TABLE).

          --DDL--Data Definition Language--數據定義語言
          create, modify,drop, or rename objects (CREATE,ALTER,DROP,RENAME),
          remove all rows from a database object without dropping the structure (TRUNCATE),
          manage access privileges (GRANT,REVOKE),
          audit database use (AUDIT,NOAUDIT)
          and add a description about an object to the dictionary (COMMENT).

          --Transaction Control事務控制語句
          save the changes(COMMIT)
          or discard the changes (ROLLBACK) made by DML statements.
          Also included in the transaction-control statements are statements to set a point or marker in the transaction for possible rollback (SAVEPOINT)
          and to define the properties for the transaction (SET TRANSACTION).
          Used to manage the properties of the database.
          There isonly one statement in this category (ALTER SYSTEM).

          --DCL--Data Control Language--與開發關系不是很密切,用于權限的分配與回收
          grant,revoke,data control

          --Session Control
          control the session properties (ALTER SESSION)
          and to enable/disable roles (SET ROLE).

          --System Control


          --------------------------------------------------------
          select的用法

          --每個員工的所有信息
          select * from emp
          --每個人的部門編號,姓名,薪水
          select deptno,ename,sal from emp;
          --每個人的年薪
          select ename,sal*12 from emp;
          --計算2*3的值
          select 2*3 from emp;
          --計算2*3的值(dual)
          select 2*3 from dual;
          select * from dual;
          --得到當前時間
          select sysdate from dual
          --可以給列起別名,比如求每個人的年薪
          select ename,sal*12  salperyear from emp;
          --如果別名中有空格,需要用雙引號
          select ename,sal*12  "sal per year" from emp;
          --如果沒有內容,則為空
          select comm from emp;
          --當空字段參與計算,則結果是null
          --例如:計算每個人的全年的收入包括月薪和年終獎
          select ename,sal*12+comm from emp;
          --可以將多個字符串拼在一起。比如:求每個人的薪水,格式為smith-sal-123
          select ename||'-sal-'||sal from emp;
          --如果字符串中有單引號,需要用另外一個單引號轉義,比如:這樣一個字符串: he's friend
          select ename||'''s sal is'||sal from emp;


          --------------------------------------------------------
          --distinct 關鍵詞的用法
          --求有哪些個部門
          select distinct deptno from emp
          --可以用來修飾多個字段。比如:求有哪些個部門和job的組合
          select distinct deptno,job from emp

          --------------------------------------------------------
          where關鍵詞的用法
          --可以是數值類型的等值判斷。比如:求10這個部門的所有員工
          select * from emp where deptno=20
          --可以是字符串類型的等值判斷。比如:求叫KING的這個人的信息
          select * from emp where ename = 'KING'
          --也可以是不等值判斷。比如:求薪水小于2000的員工信息
          select * from emp where sal<2000;
          --字符串也可以做不等值判斷,比如:求所有ename大于'CBA'的員工信息。
          select * from emp where ename>'CBA';
          --求部門不是10的員工
          select * from emp where deptno <> 10;
          --求薪水在800和1500之間的員工信息
          select * from emp where sal >=800 and sal <=1500;
          --也可以寫成
          select * from emp where sal between 800 and 1500
          --這樣寫則不可以
          -----------------------------select * from emp where 800<=sal<=1500
          --where...in..的用法。比如:求薪水是800或者1500或正2000的員工信息
          select * from emp where sal=800 or sal=1500 or sal=2000
          --相當于寫成這樣
          select * from emp where sal in(1500,800,2000,1500,1500,1500,1500);
          --再比如求姓名是KING,SMITH,AA的員工信息
          select * from emp where ename in ('KING','SMITH','AA')
          --求入職時間在20-2月-81之后的員工信息
          select * from emp where hiredate < '23-5月 -87';

          --------------------------------------------------------
          --and or not的用法
          --求薪水大于1000或者部門在20這個部門的員工信息
          select * from emp where sal>1000 and deptno=20
          --求薪水不是800或者不是1500或者不是3000的員工信息
          select * from emp where sal not in (800,1500,3000)
          --也可以這樣來寫
          select * from emp where sal <>800 and sal <> 1500 and sal<>3000

          --------------------------------------------------------
          --like的用法
          --求名字中包含ALL這三個字符的員工信息
          select * from emp where ename like '%E%';
          --求名字中的第二個字母是A的員工
          select * from emp where ename like '_A%';
          --特殊字符需要轉義。比如:求員工中包含特殊字符%的員工信息
          select * from emp where ename like '%\%%' escape '\'

          --------------------------------------------------------
          --null的用法
          --求沒有年終獎的員工
          select * from emp where comm is null
          --求有年終獎的員工
          select * from emp where comm is not null


          --------------------------------------------------------
          --order by的用法
          --員工信息按照姓名正序排列
          select * from emp order by ename asc;
          --員工信息按照倒敘排列
          select * from emp order by ename desc;
          --也可以是多個字段組合排列。例如:員工信息按照部門正序排列,并且按照姓名倒敘排列
          select * from emp order by deptno asc,ename desc

          --------------------------------------------------------
          --function的用法
          --把所有姓名變成小寫
          select lower(ename) from emp;
          --把所有姓名變成大寫
          select upper(ename) from emp;
          --求所有人名中包含'a'的員工信息不區分大小寫
          select * from emp where lower(ename) like '%a%'
          --截取子字符串,比如求Hello的一部分
          select substr('hello',2,2) from dual;
          select substr(ename,2,2) from emp;
          --求Hello的一部分,并指明長度

          --求ascii碼對應的字符
          select chr(65) from dual
          --求字符對應的ascii碼
          select ascii('中')from dual
          --四舍五入
          select round(12.456,2) from dual
          select round(12.456,-1) from dual
          --四舍五入小數點后面多少位

          --四舍五入小數點前面多少位


          --------------------------------------------------------
          --important!日期轉換函數
          --------------------------------------------------------
          --將當前日期轉換成1981-03-12 12:00:00這種形式的字符串
          select to_char(sysdate,'YYYY-MM-DD HH24:MI:SS') from dual;

          --將1981-03-12 12:00:00字符串轉換成日期
          select to_date('1981-03-12 12:00:00','YYYY-MM-DD HH24:MI:SS') from dual;

          --將每個人的薪水轉換成固定格式的字符串
          select to_char(sal,'$999,999,999.99') from emp;
          --將固定格式的字符串轉換成數值
          select to_number('$8,000.00','$999,999,999.99') from dual;

          --當null參與計算時候,可以用nvl這個函數。比如求每個人一年總共的收入
          select ename,sal*12+comm from emp

          --------------------------------------------------------
          --group function組函數
          --求所有人的薪水的總和,平均值,最大值,最小值
          select sum(sal),avg(sal),max(sal) ,min(sal) from emp;
          --求總的行數
          select count(*) from emp;
          --求總的行樹,(可以指定具體的字段)但如果字段有null值的時候需要小心使用
          select count(comm) from emp;

          --也可以過濾掉重復的行之后統計行數

          select count(distinct deptno) from emp
          --可以指明按照哪個字段進行分組.比如;分部門統計最高薪水
          select deptno,max(sal) from emp where deptno is not null group by deptno
          --也可以按照多個字段來分組統計,比如:分部門和崗位,統計最高薪水和行數
          select deptno,job,max(sal),count(*) from emp group by deptno,job

          --------------------------------------------------------
          --重要:出現在select列表中的字段,如果沒有在組函數中,那么必須出現在group by 子句中。
          --------------------------------------------------------
          select ename,deptno,job,max(sal),count(*) from emp group by deptno,job

          --求薪水最高的員工姓名
          select * from emp where sal=(select max(sal) from emp);
          delete from emp where ename='TEST2'
          update emp set deptno=10 where deptno=99
          select * from dept
          insert into dept (deptno,dname,loc) values('10','ACCOUNTING','NEW YORK');
          --having從句的用法
          --求平均薪水是2000以上的部門
          select deptno,avg(sal) as avg_sal from emp group by deptno
          having avg(sal) >2000
          --------------------------------------------------------
          --總結一下select語法
          select
          from
          where
          group by
          having
          order by
          --------------------------------------------------------
          -- 執行順序very important!
          -- 首先執行where語句將原有記錄過濾;
          -- 第二執行group by 進行分組;
          -- 第三執行having過濾分組;
          -- 然后將select 中的字段值選出來;
          -- 最后執行order by 進行排序;

          --------------------------------------------------------
          /*
          按照部門分組統計,求最高薪水,平均薪水
          只有薪水是1200以上的才參與統計
          并且分組結果中只包括平均薪水在1500以上的部門
          而且按照平均薪水倒敘排列
          */
          select max(sal),avg(sal) from emp
          where sal>1200
          group by deptno
          having avg(sal) >1500
          order by avg(sal) desc

          --------------------------------------------------------
          /*
          把雇員按部門分組,
          求最高薪水, 部門號,
          過濾掉名字中第二個字母是'A'的,
          要求分組后的平均薪水>1500,
          按照部門編號倒序排列
          */
          select max(sal) ,deptno from emp where ename not like '_A%'group by deptno
          having avg(sal) >1500
          order by deptno desc

          /* very very important! */
          select ename, deptno from emp;
          select deptno, dname from dept;
          --------------------------------------------------------------------------------------
          --老語法:----------------------------------------------------------------------------
          --------------------------------------------------------------------------------------
          --等值連接:求員工姓名以及員工所在部門的名字同時顯示出來
          select ename,emp.deptno,dname,dept.deptno from emp,dept
          where emp.deptno = dept.deptno

          select ename,e.deptno,dname,d.deptno from emp e,dept d
          where e.deptno = d.deptno

          --非等值連接:要求每位雇員的薪水等級
          select * from salgrade
          select ename,sal,grade,losal,hisal from emp,salgrade
          where sal >=losal and sal <=hisal
          --跨3個表:求工作職位是’PRESIDENT’的雇員姓名,部門名稱和薪水等級時
          select ename,dname,grade from emp,dept,salgrade
          where emp.deptno = dept.deptno
          and sal >=losal and sal <=hisal
          and job ='PRESIDENT'


          --也可以同一個表做跨表連接:求每位員工的姓名,及其上級經理的姓名

          select e1.ename,e2.ename from emp e1,emp e2
          where e1.mgr = e2.empno

          --------------------------------------------------------------------------------------
          --新語法------------------------------------------------------------------------------
          --在SQL1992的語法規則中,語句過濾的條件和表連接的條件都被放在了where子句中,當條件過多時,容易造成混淆,
          --SQL1999修正了這個缺點,將連接條件和數據過濾條件區分開來,
          --------------------------------------------------------------------------------------

          --交叉連接
          --結果會產生這兩張表的笛卡爾乘積

          select * from emp cross join dept
          --要用deptno作為等值連接條件,我們可以這樣寫
          select * from emp join dept using (deptno)
          select ename, dname from emp join dept using(deptno);
          --相當于
          select ename, dname from emp join dept on emp.deptno = dept.deptno
          --也可以寫成這樣


          --也可以用于非等值連接
          --求每位雇員的薪水等級
          select * from emp join salgrade on (sal >=losal and sal<= hisal)


          --多個join,where組合使用
          --(求工作職位是’PRESIDENT’的雇員姓名,部門名稱和薪水等級時)

          select * from emp join dept on emp.deptno = dept.deptno
          join salgrade on (sal >=losal and sal<= hisal)
          where job = 'PRESIDENT'


          --外連接--取出表中連接不到一起的多余的數據
          --沒有全內連接,沒有右內連接

          --其中outer也可以省略,簡寫為left join , right join , full join
          --left inner join可以縮寫成inner join 也可以縮寫成join,意思是左內。
          --update emp set deptno=20 where ename='SMITH';
          --commit;
          select * from emp;
          select * from dept;
          delete from dept where deptno=99;
          --左內,從左往右找,匹配不上的記錄不顯示
          select ename,emp.deptno from emp  join dept on emp.deptno = dept.deptno;
          select ename,emp.deptno from emp  inner join dept on emp.deptno = dept.deptno;
          --沒有這種語法:select ename,emp.deptno from emp  left inner join dept on emp.deptno = dept.deptno;
          --左外連接,從左往右找,匹配不上的記錄也顯示一行
          select ename,dept.deptno from emp left /*outer*/ join dept on emp.deptno = dept.deptno;

          --右外連接,從右往左找,匹配不上的記錄,也顯示一行
          select ename,dept.deptno from emp right /*outer*/ join dept on emp.deptno = dept.deptno;
          --沒有右內連接:select ename,dept.deptno from emp right inner join dept on emp.deptno = dept.deptno;

          --全外連接
          select ename,dept.deptno from emp full /*outer*/ join dept on emp.deptno = dept.deptno;

          --左外,右外的區別






          --什么時候用外連接呢?比如領導向你要所有學生的列表,順便把所屬的班級也列出來,就需要外連接

          --在Where語句中使用子查詢
          -----------------------------------------------------------------
          --雇員中最高薪水的人員名稱
          --1,先求出最高薪水
          --2,再求雇員中最高薪水的人員名稱
          select ename from emp where sal=(select max(sal) from emp)



          --有哪些人的薪水是在整個雇員的平均薪水之上的
          select ename,sal from emp where sal >(select avg(sal) from emp)

          -----------------------------------------------------------------
          --雇員中哪些人是經理人
          --1,首先查詢mgr中有哪些號碼
          --2,再看有哪些人員的號碼在此出現
          select distinct mgr from emp where mgr is not null order by mgr

          select ename
            from emp
          where empno in (select distinct mgr from emp where mgr is not null )
          --where in 中不讓寫orderby
          select ename
            from emp
          where empno in (select distinct mgr from emp where mgr is not null order by mgr)

          -----------------------------------------------------------------
          --在From子句中使用子查詢
          ------------------------------------------------------------------

          --部門平均薪水的等級
          --1,首先將每個部門的平均薪水求出來
          --2,然后把結果當成一張表,再用這張結果表和salgrade表做連接,以此求得薪水等級
          select deptno,avg(sal) from emp group by deptno
          select * from (select deptno,avg(sal) avg_sal from emp group by deptno) t join salgrade
          on avg_sal between losal and hisal;


          -----------------------------------------------------------------
          --每個部門最高薪水的人員名稱
          --1,首先將每個部門的最高薪水求出來
          --2,然后把結果當成一張表,再用emp和這張結果表做連接,以此求得每個部門最高薪水的人員名稱

          select deptno,max(sal) from emp where deptno is not null group by deptno

          select ename from emp e join
          (select deptno,max(sal) max_sal from emp where deptno is not null group by deptno ) t
          on sal = max_sal and e.deptno = t.deptno

          -----------------------------------------------------------------
          --哪些人的薪水在部門的平均薪水之上
          --1,首先將每個部門的平均薪水求出來
          --2,然后把結果當成一張表,再用emp和這張結果表做連接,以此求得哪些人的薪水在部門的平均薪水之上
          select deptno,avg(sal) avg_sal from emp group by deptno

          select * from emp join (select deptno,avg(sal) avg_sal from emp group by deptno)t
          on (sal>avg_sal and emp.deptno=t.deptno)
          -----------------------------------------------------------------
          --求部門中(所有人的)平均的薪水等級,形式如:
          --  deptno  avg_grade
          --  10      3.67
          --  20      2.8
          --  30      2.5
          --1,先求每個人的薪水等級
          --2,再按照部門分組,求平均數
          select deptno,sal,grade from emp join salgrade on sal between losal and hisal
          select deptno,avg(grade) from (select deptno,sal,grade from emp join salgrade on sal between losal and hisal)t group by deptno




          ------------------------------------------------------------------------------------------
          --使用偽字段:rownum,----------------------
          ------------------------------------------------------------------------------------------
          --用來標識每條記錄的行號,行號從1開始,每次遞增1
          select rownum,emp.* from emp;
          --oracle下rownum只能使用 < <=, 不能使用 = > >= 等比較操作符,
          select rownum,emp.* from emp where rownum<5;
          --當rownum和order by 一起使用時,會首先選出符合rownum條件的記錄,然后再排序
          --(錯誤的寫法)例如,當我們要求薪水最高的前5個人時,最直接的想法可以這樣寫:
          select * from emp where rownum<5 order by sal desc
          --(正確的寫法)可以這樣寫

          select * from
          (select * from emp order by sal desc) t
          where rownum<=5




          --------------------------------------------------------
          --不準用組函數(即MAX()),求薪水的最高值(面試題)
          --第一種解決辦法:
          --1,先把所有薪水按照倒序排列
          --2,再取第一行
          select * from
          (select sal from emp order by sal desc) t
          where rownum=1



          --第二種解決辦法:
          --1,先跨表查詢自己,先求出的結果中,e1.sal不可能出現最大數
          --2,然后再not in
          select e2.sal from emp e1,emp e2 where e1.sal>e2.sal
          select sal from emp where sal not in(select e2.sal from emp e1,emp e2 where e1.sal>e2.sal)


          -----------------------------------------------------------------
          --求平均薪水最高的部門的部門編號
          --第一種解決辦法:
          --1,先求出每個部門的平均薪水,
          select deptno,avg(sal) avg_sal from emp group by deptno
          --2,再求每個部門的平均薪水的最高值,
          select max(avg_sal) from (1111111111111111111111111)
          --3,最后再求第一步結果中avg_sal = 最高薪水的記錄.

          select deptno from (111111111111) where avg_sal = (22222222)


          select deptno
            from (select deptno,avg(sal) avg_sal from emp group by deptno)
          where avg_sal =
                 (select max(avg_sal)
                    from (select deptno,avg(sal) avg_sal from emp group by deptno))


          --沒法考慮并列第一的情況
          select deptno from
          (select deptno,avg(sal) avg_sal from emp group by deptno order by avg(sal) desc)
          where rownum<=1


          --第二種解決辦法:
          --1,將上面的第一步第二步合并,先求最高平均薪水,用max(avg(sal))的辦法
          --不能寫成select deptno,max(avg(sal)) from emp group by deptno
          select max(avg(sal)) from emp group by deptno
          --2,求出每個部門的平均薪水
          select deptno,avg(sal) avg_sal from emp group by deptno
          --3,最后再求第二步結果中(即每個部門的平均薪水),avg_sal = (第一步結果)的記錄.即avg_sal =最高薪水的記錄.
          select deptno from (select deptno,avg(sal) avg_sal from emp group by deptno)
          where avg_sal =(select max(avg(sal)) from emp group by deptno)


          --第三種解決辦法:
          --1,先求出每個部門的平均薪水,
          select avg(sal) avg_sal from emp group by deptno
          --2,求最高平均薪水,用max(avg(sal))的辦法
          select max(avg(sal)) from emp group by deptno
          --3,再使用having語句, avg(sal) = 第二步的結果
          注意:為組函數起的別名在having中不能用

          select deptno from emp group by deptno
          having avg(sal) = (select max(avg(sal)) from emp group by deptno)



          -----------------------------------------------------------------
          --求平均薪水最高的部門的部門名稱
          --1,部門平均最高薪水
          --2,得到部門編號列表,注意用group by deptno
          --3,再應用having子句, having avg(sal) = (第一步的結果)
          --4,得到平均最高薪水的那個部門的編號
          --5,再得到部門名稱



          select dname from dept where deptno in

          (
          select deptno
            from (select deptno,avg(sal) avg_sal from emp group by deptno)
          where avg_sal =
                 (select max(avg_sal)
                    from (select deptno,avg(sal) avg_sal from emp group by deptno))

          )

          -----------------------------------------------------------------
          --求平均薪水的等級最低的部門的部門名稱
          --第一步:部門平均薪水的等級,分成兩個小步驟,第一小步是求部門平均薪水

          select * from
          (select deptno,avg(sal) avg_sal from emp group by deptno) t
          join salgrade on avg_sal between losal and hisal

          --第二步:最低的等級值

          select min(grade) from (1111111111111111111111111)

          --第三步:等于最低值的部門編號
          ------------有錯誤,應該是grade=
          select deptno from (111111111111) where grade = (22222222222222)
          --第四步:求名稱
          select dname from dept where deptno in(33333333333)




          select dname
            from dept
          where deptno in
                 (
                 
                  select deptno
                    from (select *
                             from (select deptno, avg(sal) avg_sal
                                     from emp
                                    group by deptno) t
                             join salgrade on avg_sal between losal and hisal)
                   where grade =
                         (select min(grade)
                            from (select *
                                    from (select deptno, avg(sal) avg_sal
                                            from emp
                                           group by deptno) t
                                    join salgrade on avg_sal between losal and hisal)))









          --也可以用視圖的方式來解決
          --conn sys/bjsxt as sysdba
          --grant create table, create view, create sequence to scott
          --根據第一步的結果,建立一個view

          create or replace view v1 as
          --必須明確定義列
          select deptno, avg_sal, grade from
          (select deptno,avg(sal) avg_sal from emp group by deptno) t
          join salgrade on avg_sal between losal and hisal


          --查看一下
          select * from v1
          --查詢一下

          --帶入view

          select dname from dept where deptno in
          (select deptno from (v1) where grade = (select min(grade) from v1))








          -------------------------------------------------------------
          --為什么in的后面不能order by ?







          ---------------------------------------------------------------
          --求部門經理人中平均薪水最低的部門名稱 (思考題)
          第一步,求部門經理的雇員編號
          select distinct mgr from emp where mgr is not null
          第二步,按部門統計,求部門經理的平均薪水
          select deptno,avg(sal) avg_sal from emp where empno in (select distinct mgr from emp where mgr is not null)group by deptno
          第三步,求最低值
          select min(avg(sal)) from emp where empno in (select distinct mgr from emp where mgr is not null)group by deptno
          第四步,求部門經理人中平均薪水最低的部門名稱
          select deptno from (2222222222222) where avg_sal =(333333333333333333333333)


          select dname from dept where deptno in (select deptno from (select deptno,avg(sal) avg_sal from emp where empno in (select distinct mgr from emp where mgr is not null)group by deptno) where avg_sal =(select min(avg(sal)) from emp where empno in (select distinct mgr from emp where mgr is not null)group by deptno))
          ----------------------------------------------------------------------------
          --求比普通員工的最高薪水還要高的經理人名稱
          --1,求所有經理的編號
          create or replace view v1 as
          select distinct mgr from emp where mgr is not null
          select * from v1
          --2,普通員工的最高薪水
          select max(sal) from emp where empno not in (select distinct mgr from emp where mgr is not null)
          --3,

          select ename from emp where empno in (select * from v1)
          and sal > (select max(sal) from emp where empno not in (select distinct mgr from emp where mgr is not null))

          --即:


          select ename from emp where empno in (select distinct mgr from emp where mgr is not null)
          and sal > (select max(sal) from emp where empno not in (select distinct mgr from emp where mgr is not null))








          ------------------------------------------------------------------------------
          --求薪水最高的前5名雇員
          --1,先觀察一下

          --2,看看rownum的作用

          --3,不是我們想要的結果
          select ename,sal  from emp where rownum<=5 order by sal desc
          --4,先order by,再rownum
          select * from
          (select ename,sal  from emp  order by sal desc ) t
          where rownum<=5

          --------------------------------------------------------------------------------
          --求薪水最高的第6到第10名雇員(重點掌握)
          --這種沒法實現,oracle下rownum只能使用 < <=, 不能使用 = > >= 等比較操作符
          --注意里面的rownum和外面的rownum的區別,外面要想訪問里面的rownum,必須取得一個別名。

          select * from
          (select ename,sal  from emp  order by sal desc ) t
          where rownum>=5
          and rownum<=10

          --所以再套一層select
          select * from
          (select t.*,rownum r from
          (select ename,sal  from emp  order by sal desc ) t
          )
          where r>=5
          and r<=10

          --還有一種排序方式
          select * from
          (select * from emp  order by sal desc)where rownum<=10
          minus
          select * from
          (select * from emp  order by sal desc)where rownum<=5
          --------------------------------------------------------------------
          --練習: 求最后入職的5名員工
          --1,每個人的入職時間

          --2,取前5行





          -----------------------------------------------------------------
          --求每個部門中薪水最高的前兩名雇員

          --1,每個員工的姓名,部門,工資,按部門和工資(倒序)排列
          select ename,deptno,sal from emp order by deptno,sal desc
          --2,套一層,加上個r
          select ename,deptno,sal,rownum r from
          (select ename,deptno,sal from emp order by deptno,sal desc) t
          --3,創建試圖
          create or replace view v1
          as
          select ename,deptno,sal,rownum r from
          (select ename,deptno,sal from emp order by deptno,sal desc) t
          --觀察一下
          select * from v1

          --每個部門中,薪水最高的第一行,并創建試圖
          create or replace view v2 as
          select deptno,min(r) min_r from v1 group by deptno

          --兩個view跨表連接,大于薪水最高的行數,小于最高的行數+1,并且部門編號要匹配
          select ename from v1 join v2
          on ( v1.deptno = v2.deptno and v1.r >=v2.min_r and v1.r<=v2.min_r+1)


          -------------------------------------------------------------------------------
          --面試題: 比較效率
            select * from emp where deptno = 10 and ename like '%A%';
            select * from emp where ename like '%A%' and deptno = 10;
           
          ---------------------------------------------------------
          --使用union、minus

          --使用union、minus可以用來實現結果集的合并和去除(可以理解為加和減),例如:
          select * from emp where deptno=10
          union
          select * from emp where deptno=20;

          --相當于
          select * from emp where deptno=10 or deptno=20

          --而下面的語句
          select * from emp where deptno in (10,20)
          minus
          select * from emp where sal < 1500;
          --相當于
          select * from emp where deptno in(10,20) and sal>=1500

          --求分段顯示薪水的個數



          如:
          scale      total
          <800    0
          801-1000 2
          1001-2000 3
          2001-5000 6
          >5000    8

          select '<800' as scale ,count(*) as total from emp where sal<800
          union
          select '<801-1000' as scale ,count(*) as total from emp where sal<=1000 and sal>=801



          --或者顯示成為
          --注意:使用between .. and .. 的時候,包含了最大和最小值。
          800-1000 1001-2000 2001-5000
          2       3       6
          select * from
          (select count(*) as "800-1000" from emp where sal >=800 and sal <= 1000),
          (select count(*) as "1001-2000" from emp where sal >=1001 and sal <= 2000),
          (select count(*) as "2001-5000" from emp where sal >=2001 and sal <= 5000)



          --或顯示成為
          DEPTNO   800-2000  2001-5000
          ------ ---------- ----------
              30          5          1
              20          2          3
              10          1          2
          select t.deptno,"800-2000","2001-5000" from
          (select deptno,count(*) as "800-2000" from emp where sal between 800 and 2000 group by deptno) t
          join
          (select deptno,count(*) as "2001-5000" from emp where sal between 2001 and 5000 group by deptno) t1
          on t.deptno = t1.deptno








            
          -----------------------------------------------------------------------------------
          --每個薪水等級有多少名雇員 ?
          --1,先求出每個雇員的薪水等級

          --2,再group一下
          posted @ 2009-04-13 10:40 lanxin1020 閱讀(190) | 評論 (0)編輯 收藏
          (轉)Hibernate支持兩種鎖機制:
          即通常所說的“悲觀鎖(Pessimistic Locking)”和
          “樂觀鎖(OptimisticLocking)”。
          悲觀鎖的實現,往往依靠數據庫提供的鎖機制(也只有數據庫層提供的鎖機制才能真正保證數據訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無法保證外部系統不會修改數據)。
          Hibernate的加鎖模式有:
          Ø LockMode.NONE : 無鎖機制。
          Ø LockMode.WRITE :Hibernate在Insert和Update記錄的時候會自動
          獲取。
          Ø LockMode.READ : Hibernate在讀取記錄的時候會自動獲取。
          以上這三種鎖機制一般由Hibernate內部使用,如Hibernate為了保證Update
          過程中對象不會被外界修改,會在save方法實現中自動為目標對象加上WRITE鎖。
          Ø LockMode.UPGRADE :利用數據庫的for update子句加鎖。
          Ø LockMode. UPGRADE_NOWAIT :Oracle的特定實現,利用Oracle的for
          update nowait子句實現加鎖。
          樂觀鎖,大多是基于數據版本(Version)記錄機制實現。何謂數據版本?即為數據增加一個版本標識,在基于數據庫表的版本解決方案中,一般是通過為數據庫表增加一個“version”字段來實現。讀取出數據時,將此版本號一同讀出,之后更新時,對此版本號加一。此時,將提交數據的版本數據與數據庫表對應記錄的當前版本信息進行比對,如果提交的數據版本號大于數據庫表當前版本號,則予以更新,否則認為是過期數據。
          悲觀鎖與樂觀鎖的比較:
          悲觀鎖大多數情況下依靠數據庫的鎖機制實現,以保證操作最大程度的獨占性。但隨之而來的就是數據庫性能的大量開銷,特別是對長事務而言,這樣的開銷往往無法承受;
          相對悲觀鎖而言,樂觀鎖機制采取了更加寬松的加鎖機制。樂觀鎖機制往往基于系統中的數據存儲邏輯,因此也具備一定的局限性,如在上例中,由于樂觀鎖機制是在我們的系統中實現,來自外部系統的更新操作不受我們系統的控制,因此可能會造成臟數據被更新到數據庫中。在
          系統設計階段,我們應該充分考慮到這些情況出現的可能性,并進行相應調整(如將樂觀鎖策略在數據庫存儲過程中實現,對外只開放基于此存儲過程的數據更新途徑,而不是將數據庫表直接對外公開)。
          Hibernate 在其數據訪問引擎中內置了樂觀鎖實現。如果不用考慮外部系統對數據庫的更新操作,利用Hibernate提供的透明化樂觀鎖實現,將大大提升我們的生產力。
          Hibernate中可以通過class描述符的optimistic-lock屬性結合version描述符指定。
          optimistic-lock屬性有如下可選取值:
          Ø none
          無樂觀鎖
          Ø version
          通過版本機制實現樂觀鎖
          Ø dirty
          通過檢查發生變動過的屬性實現樂觀鎖
          Ø all
          通過檢查所有屬性實現樂觀鎖
          其中通過version實現的樂觀鎖機制是Hibernate官方推薦的樂觀鎖實現,同時也是Hibernate中,目前唯一在數據對象脫離 Session發生修改的情況下依然有效的鎖機制。因此,一般情況下,我們都選擇version方式作為Hibernate樂觀鎖實現機制。
          posted @ 2009-04-12 16:12 lanxin1020 閱讀(184) | 評論 (0)編輯 收藏

          使用Hibernate自帶的工具hbm2ddl,建立根據你的對象建立數據庫:

          首先建好POJO object, XML Mapping File(也可以使用工具根據POJO class建立),配置文件(hibernate.cfg.xml)

          Java代碼


          import org.hibernate.cfg.Configuration;
          import org.hibernate.tool.hbm2ddl.SchemaExport;
          
          public class SchemaUtil {
          public static void main(String[] args) {

          Configuration cfg = new Configuration().configure(); SchemaExport schemaExport= new SchemaExport(cfg); schemaExport.create(false, true); } }
          posted @ 2009-04-11 16:31 lanxin1020 閱讀(165) | 評論 (0)編輯 收藏
          僅列出標題
          共7頁: 上一頁 1 2 3 4 5 6 7 下一頁 
          主站蜘蛛池模板: 搜索| 桦南县| 资兴市| 仁怀市| 航空| 邵阳市| 罗平县| 琼海市| 星座| 大同县| 游戏| 马公市| 惠来县| 西乌珠穆沁旗| 宜兰县| 大庆市| 息烽县| 扬州市| 辽源市| 棋牌| 大丰市| 茂名市| 金沙县| 博湖县| 泰州市| 黄石市| 易门县| 天全县| 昭通市| 清新县| 南雄市| 海口市| 鱼台县| 赤水市| 阳朔县| 瓦房店市| 望都县| 景谷| 定日县| 东明县| 巴彦县|