<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    少年阿賓

    那些青春的歲月

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

    #

         摘要: Struts2攔截器(Interceptor)                              &...  閱讀全文
    posted @ 2012-03-14 23:35 abin 閱讀(698) | 評論 (0)編輯 收藏

    MYSQL中 ENUM 類型的詳細解釋

    ENUM 類型

    ENUM 是一個字符串對象,其值通常選自一個允許值列表中,該列表在表創建時的列規格說明中被明確地列舉。

    在下列某些情況下,值也可以是空串("") 或 NULL

    • 如果將一個無效值插入一個 ENUM (即,一個不在允許值列表中的字符串),空字符串將作為一個特殊的錯誤值被插入。事實上,這個字符串有別于一個"普通的"空字符串,因為這個字符串有個數字索引值為 0。稍后有更詳細描述。
    • 如果一個 ENUM 被聲明為 NULLNULL 也是該列的一個合法值,并且該列的缺省值也將為 NULL 。如果一個 ENUM 被聲明為 NOT NULL,該列的缺省值將是該列表所允許值的第一個成員。

    每個枚舉值均有一個索引值:

    • 在列說明中列表值所允許的成員值被從 1 開始編號。
    • 空字符串錯誤值的索引值為 0。這就意味著,你可以使用下面所示的 SELECT 語句找出被賦于無效 ENUM 值的記錄行。
      mysql> SELECT * FROM tbl_name WHERE enum_col=0;
    • NULL 值的索引值為 NULL。

    例如,指定為 ENUM("one", "two", "three") 的一個列,可以有下面所顯示的任一值。每個值的索引值也如下所示:

    索引值
    NULL NULL
    "" 0
    "one" 1
    "two" 2
    "three" 3

    換個枚舉最大可以有 65535 個成員值。

    從 MySQL 3.23.51 開始,當表被創建時,ENUM 值尾部的空格將會自動刪除。

    當為一個 ENUM 列賦值時,字母的大小寫是無關緊要的。然而,以后從列中檢索出來的值的大小寫卻是匹配于創建表時所指定的允許值。

    如果在一個數字語境中檢索一個ENUM,列值的索引值將被返回。例如,你可以像這樣使用數字值檢索一個 ENUM 列:

    mysql> SELECT enum_col+0 FROM tbl_name;

    如果將一個數字存儲到一個 ENUM 中,數字被當作為一個索引值,并且存儲的值是該索引值所對應的枚舉成員。(但是,這在 LOAD DATA 將不能工作,因為它視所有的輸入均為字符串。) 在一個 ENUM 字符串中存儲數字是不明智的,因為它可能會打亂思維。

    ENUM 值依照列規格說明中的列表順序進行排序。(換句話說,ENUM 值依照它們的索引號排序。)舉例來說,對于 ENUM("a", "b") "a" 排在 "b" 后,但是對于 ENUM("b", "a") "b" 卻排在 "a" 之前。空字符串排在非空字符串前,NULL 值排在其它所有的枚舉值前。為了防止意想不到的結果,建議依照字母的順序定義 ENUM 列表。也可以通過使用 GROUP BY CONCAT(col) 來確定該以字母順序排序而不是以索引值。

    如果希望得到一個 ENUM 列的所有可能值,可以使用 SHOW COLUMNS FROM table_name LIKE enum_colum

    posted @ 2012-03-12 23:31 abin 閱讀(514) | 評論 (0)編輯 收藏

    一、MySQL 字段數據類型/長度

    1、數值類型

    列類型              需要的存儲量 
    TINYINT                1 字節 
    SMALLINT             2 個字節 
    MEDIUMINT          3 個字節 
    INT                       4 個字節 
    INTEGER             4 個字節 
    BIGINT                 8 個字節 
    FLOAT(X)           4 如果 X < = 24 或 8 如果 25 < = X < = 53 
    FLOAT                 4 個字節 
    DOUBLE              8 個字節 
    DOUBLE PRECISION     8 個字節 
    REAL                    8 個字節 
    DECIMAL(M,D)   M字節(D+2 , 如果M < D) 
    NUMERIC(M,D)   M字節(D+2 , 如果M < D)

    MySQL 的數值數據類型可以大致劃分為兩個類別,一個是整數,另一個是浮點數或小數。許多不同的子類型對這些類別中的每一個都是可用的,每個子類型支持不同大小的數據,并且 MySQL 允許我們指定數值字段中的值是否有正負之分或者用零填補。

      表列出了各種數值類型以及它們的允許范圍和占用的內存空間。

    類型
    大小
    范圍(有符號)
    范圍(無符號)
    用途
    TINYINT
    1 字節
    (-128,127)
    (0,255)
    小整數值
    SMALLINT
    2 字節
    (-32 768,32 767)
    (0,65 535)
    大整數值
    MEDIUMINT
    3 字節
    (-8 388 608,8 388 607)
    (0,16 777 215)
    大整數值
    INT或INTEGER
    4 字節
    (-2 147 483 648,2 147 483 647)
    (0,4 294 967 295)
    大整數值
    BIGINT
    8 字節
    (-9 233 372 036 854 775 808,9 223 372 036 854 775 807)
    (0,18 446 744 073 709 551 615)
    極大整數值
    FLOAT
    4 字節
    (-3.402 823 466 E+38,1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38)
    0,(1.175 494 351 E-38,3.402 823 466 E+38)
    單精度
    浮點數值
    DOUBLE
    8 字節
    (1.797 693 134 862 315 7 E+308,2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308)
    0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308)
    雙精度
    浮點數值
    DECIMAL
    對DECIMAL(M,D) ,如果M>D,為M+2否則為D+2
    依賴于M和D的值
    依賴于M和D的值
    小數值

    INT 類型

      在 MySQL 中支持的 5 個主要整數類型是 TINYINT,SMALLINT,MEDIUMINT,INT 和 BIGINT。這些類型在很大程度上是相同的,只有它們存儲的值的大小是不相同的。

      MySQL 以一個可選的顯示寬度指示器的形式對 SQL 標準進行擴展,這樣當從數據庫檢索一個值時,可以把這個值加長到指定的長度。例如,指定一個字段的類型為 INT(6),就可以保證所包含數字少于 6 個的值從數據庫中檢索出來時能夠自動地用空格填充。需要注意的是,使用一個寬度指示器不會影響字段的大小和它可以存儲的值的范圍。

      萬一我們需要對一個字段存儲一個超出許可范圍的數字,MySQL 會根據允許范圍最接近它的一端截短后再進行存儲。還有一個比較特別的地方是,MySQL 會在不合規定的值插入表前自動修改為 0。

      UNSIGNED(未簽署) 修飾符規定字段只保存正值。因為不需要保存數字的正、負符號,可以在儲時節約一個“位”的空間。從而增大這個字段可以存儲的值的范圍。

      ZEROFILL(零填充) 修飾符規定 0(不是空格)可以用來真補輸出的值。使用這個修飾符可以阻止 MySQL 數據庫存儲負值。

    FLOAT、DOUBLE 和 DECIMAL 類型

      MySQL 支持的三個浮點類型是 FLOAT、DOUBLE 和 DECIMAL 類型。FLOAT 數值類型用于表示單精度浮點數值,而 DOUBLE 數值類型用于表示雙精度浮點數值。

      與整數一樣,這些類型也帶有附加參數:一個顯示寬度指示器和一個小數點指示器。比如語句 FLOAT(7,3) 規定顯示的值不會超過 7 位數字,小數點后面帶有 3 位數字。

      對于小數點后面的位數超過允許范圍的值,MySQL 會自動將它四舍五入為最接近它的值,再插入它。

      DECIMAL 數據類型用于精度要求非常高的計算中,這種類型允許指定數值的精度和計數方法作為選擇參數。精度在這里指為這個值保存的有效數字的總個數,而計數方法表示小數點后數字的位數。比如語句 DECIMAL(7,3) 規定了存儲的值不會超過 7 位數字,并且小數點后不超過 3 位。

      忽略 DECIMAL 數據類型的精度和計數方法修飾符將會使 MySQL 數據庫把所有標識為這個數據類型的字段精度設置為 10,計算方法設置為 0。

      UNSIGNED(未簽署) 和 ZEROFILL(零填充) 修飾符也可以被 FLOAT、DOUBLE 和 DECIMAL 數據類型使用。并且效果與 INT 數據類型相同。

    2、日期和時間類型

    列類型                  需要的存儲量 
    DATE                        3 個字節 
    DATETIME                8 個字節 
    TIMESTAMP             4 個字節 
    TIME                         3 個字節 
    YEAR                        1 字節

          在處理日期和時間類型的值時,MySQL 帶有 5 個不同的數據類型可供選擇。它們可以被分成簡單的日期、時間類型,和混合日期、時間類型。根據要求的精度,子類型在每個分類型中都可以使用,并且 MySQL 帶有內置功能可以把多樣化的輸入格式變為一個標準格式

    類型
    大小
    (字節)
    范圍
    格式
    用途
    DATE
    3
    1000-01-01/9999-12-31
    YYYY-MM-DD
    日期值
    TIME
    3
    '-838:59:59'/'838:59:59'
    HH:MM:SS
    時間值或持續時間
    YEAR
    1
    1901/2155
    YYYY
    年份值
    DATETIME
    8
    1000-01-01 00:00:00/9999-12-31 23:59:59
    YYYY-MM-DD HH:MM:SS
    混合日期和時間值
    TIMESTAMP
    8
    1970-01-01 00:00:00/2037 年某時
    YYYYMMDD HHMMSS
    混合日期和時間值,時間戳

    DATE、TIME 和 TEAR 類型

      MySQL 用 DATE 和 TEAR 類型存儲簡單的日期值,使用 TIME 類型存儲時間值。這些類型可以描述為字符串或不帶分隔符的整數序列。如果描述為字符串,DATE 類型的值應該使用連字號作為分隔符分開,而 TIME 類型的值應該使用冒號作為分隔符分開。

      需要注意的是,沒有冒號分隔符的 TIME 類型值,將會被 MySQL 理解為持續的時間,而不是時間戳。

      MySQL 還對日期的年份中的兩個數字的值,或是 SQL 語句中為 TEAR 類型輸入的兩個數字進行最大限度的通譯。因為所有 TEAR 類型的值必須用 4 個數字存儲。MySQL 試圖將 2 個數字的年份轉換為 4 個數字的值。把在 00-69 范圍內的值轉換到 2000-2069 范圍內。把 70-99 范圍內的值轉換到 1970-1979 之內。如果 MySQL 自動轉換后的值并不符合我們的需要,請輸入 4 個數字表示的年份。

    DATETIME 和 TIMESTAMP 類型

       除了日期和時間數據類型,MySQL 還支持 DATEYIME 和 TIMESTAMP 這兩種混合類型。它們可以把日期和時間作為單個的值進行存儲。這兩種類型通常用于自動存儲包含當前日期和時間的時間戳,并可在需要執行大量數據庫事務和需要建立一個調試和審查用途的審計跟蹤的應用程序中發揮良好作用。

      如果我們對 TIMESTAMP 類型的字段沒有明確賦值,或是被賦與了 null 值。MySQL 會自動使用系統當前的日期和時間來填充它。

    3、字符串類型

    列類型                            需要的存儲量 
    CHAR(M)                         M字節,1 <= M <= 255 
    VARCHAR(M)                  L+1 字節, 在此L <= M和1 <= M <= 255 
    TINYBLOB, TINYTEXT     L+1 字節, 在此L< 2 ^ 8 
    BLOB, TEXT                   L+2 字節, 在此L< 2 ^ 16 
    MEDIUMBLOB, MEDIUMTEXT            L+3 字節, 在此L< 2 ^ 24 
    LONGBLOB, LONGTEXT                   L+4 字節, 在此L< 2 ^ 32 
    ENUM('value1','value2',...)               1 或 2 個字節, 取決于枚舉值的數目(最大值65535) 
    SET('value1','value2',...)                  1,2,3,4或8個字節, 取決于集合成員的數量(最多64個成員)

          MySQL 提供了 8 個基本的字符串類型,可以存儲的范圍從簡單的一個字符到巨大的文本塊或二進制字符串數據。

    類型
    大小
    用途
    CHAR
    0-255字節
    定長字符串
    VARCHAR
    0-255字節
    變長字符串
    TINYBLOB
    0-255字節
    不超過 255 個字符的二進制字符串
    TINYTEXT
    0-255字節
    短文本字符串
    BLOB
    0-65 535字節
    二進制形式的長文本數據
    TEXT
    0-65 535字節
    長文本數據
    MEDIUMBLOB
    0-16 777 215字節
    二進制形式的中等長度文本數據
    MEDIUMTEXT
    0-16 777 215字節
    中等長度文本數據
    LOGNGBLOB
    0-4 294 967 295字節
    二進制形式的極大文本數據
    LONGTEXT
    0-4 294 967 295字節
    極大文本數據

    CHAR 和 VARCHAR 類型

      CHAR 類型用于定長字符串,并且必須在圓括號內用一個大小修飾符來定義。這個大小修飾符的范圍從 0-255。比指定長度大的值將被截短,而比指定長度小的值將會用空格作填補。

      CHAR 類型可以使用 BINARY 修飾符。當用于比較運算時,這個修飾符使 CHAR 以二進制方式參于運算,而不是以傳統的區分大小寫的方式。

      CHAR 類型的一個變體是 VARCHAR 類型。它是一種可變長度的字符串類型,并且也必須帶有一個范圍在 0-255 之間的指示器。CHAR 和 VARCHGAR 不同之處在于 MuSQL 數據庫處理這個指示器的方式:CHAR 把這個大小視為值的大小,不長度不足的情況下就用空格補足。而 VARCHAR 類型把它視為最大值并且只使用存儲字符串實際需要的長度(增加一個額外字節來存儲字符串本身的長度)來存儲值。所以短于指示器長度的 VARCHAR 類型不會被空格填補,但長于指示器的值仍然會被截短。

      因為 VARCHAR 類型可以根據實際內容動態改變存儲值的長度,所以在不能確定字段需要多少字符時使用 VARCHAR 類型可以大大地節約磁盤空間、提高存儲效率。

      VARCHAR 類型在使用 BINARY 修飾符時與 CHAR 類型完全相同。

    TEXT 和 BLOB 類型

      對于字段長度要求超過 255 個的情況下,MySQL 提供了 TEXT 和 BLOB 兩種類型。根據存儲數據的大小,它們都有不同的子類型。這些大型的數據用于存儲文本塊或圖像、聲音文件等二進制數據類型。

      TEXT 和 BLOB 類型在分類和比較上存在區別。BLOB 類型區分大小寫,而 TEXT 不區分大小寫。大小修飾符不用于各種 BLOB 和 TEXT 子類型。比指定類型支持的最大范圍大的值將被自動截短。

    3、復合類型

      MySQL 還支持兩種復合數據類型 ENUM 和 SET,它們擴展了 SQL 規范。雖然這些類型在技術上是字符串類型,但是可以被視為不同的數據類型。一個 ENUM 類型只允許從一個集合中取得一個值;而 SET 類型允許從一個集合中取得任意多個值。

    ENUM 類型

      ENUM 類型因為只允許在集合中取得一個值,有點類似于單選項。在處理相互排拆的數據時容易讓人理解,比如人類的性別。ENUM 類型字段可以從集合中取得一個值或使用 null 值,除此之外的輸入將會使 MySQL 在這個字段中插入一個空字符串。另外如果插入值的大小寫與集合中值的大小寫不匹配,MySQL 會自動使用插入值的大小寫轉換成與集合中大小寫一致的值。

       ENUM 類型在系統內部可以存儲為數字,并且從 1 開始用數字做索引。一個 ENUM 類型最多可以包含 65536 個元素,其中一個元素被 MySQL 保留,用來存儲錯誤信息,這個錯誤值用索引 0 或者一個空字符串表示。

      MySQL 認為 ENUM 類型集合中出現的值是合法輸入,除此之外其它任何輸入都將失敗。這說明通過搜索包含空字符串或對應數字索引為 0 的行就可以很容易地找到錯誤記錄的位置。

    SET 類型

      SET 類型與 ENUM 類型相似但不相同。SET 類型可以從預定義的集合中取得任意數量的值。并且與 ENUM 類型相同的是任何試圖在 SET 類型字段中插入非預定義的值都會使 MySQL 插入一個空字符串。如果插入一個即有合法的元素又有非法的元素的記錄,MySQL 將會保留合法的元素,除去非法的元素。

      一個 SET 類型最多可以包含 64 項元素。在 SET 元素中值被存儲為一個分離的“位”序列,這些“位”表示與它相對應的元素。“位”是創建有序元素集合的一種簡單而有效的方式。并且它還去除了重復的元素,所以 SET 類型中不可能包含兩個相同的元素。

      希望從 SET 類型字段中找出非法的記錄只需查找包含空字符串或二進制值為 0 的行。

    二、MySQL 數據表類型說明

    1. MyISAM 表 MyISAM 存儲格式自版本3.23 以來是 MySQL 中的缺省類型,它有下列特點:
    ■ 如果操作系統自身允許更大的文件,那么文件比 ISAM 存儲方法的大。
    ■ 數據以低字節優先的機器獨立格式存儲。這表示可將表從一種機器拷貝到另一種機器,即使它們的體系結構不同也可以拷貝。
    ■ 數值索引值占的存儲空間較少,因為它們是按高字節優先存儲的。索引值在低位字節中變化很快,因此高位字節更容易比較。
    ■ AUTO_INCREMENT 處理比 ISAM 的表更好。
    ■ 減少了幾個索引限制。例如,可對含 NULL 值的列進行索引,還可以對 BLOB 和 TEXT 類型的列進行索引。
    ■ 為了改善表的完整性檢查,每個表都具有一個標志,在 myisamchk 對表進行過檢查后,設置該標志。可利用 myisamchk - fast 跳過對自前次檢查以來尚未被修改過表的檢查,這樣使此管理任務更快。表中還有一個指示表是否正常關閉的標志。如果服務器關閉不正常,或機器崩潰,此標志可用來檢測出服務器起動時需要檢查的表。

    2. ISAM 表 ISAM 存儲格式是 MySQL3.23 所用的最舊的格式,但當前仍然可用。通常,相對于 ISAM 表來說,寧可使用 MyISAM 表,因為它們的限制較少。對 ISAM 表的支持隨著此存儲格式被 MyISAM 表格式所支持很有可能會逐漸消失。

    3. HEAP 表 HEAP 存儲格式建立利用定長行的內存中的表,這使表運行得非??臁T诜掌魍V箷r,它們將會消失。在這種意義上,這些表是臨時的。但是,與用 CREATE TEMPORARY TABLE 所創建的臨時表相比,HEAP 表是其他客戶機可見的。HEAP 表有幾個限制,這些限制對 MyISAM 或 ISAM 表沒有,如下所示:
    ■ 索引僅用于“=”和“< = >”比較。
    ■ 索引列中不能有 NULL 值。
    ■ 不能使用 BLOB 和 TEXT 列。
    ■ 不能使用 AUTO_INCREMENT 列。 

    posted @ 2012-03-12 22:58 abin 閱讀(1756) | 評論 (0)編輯 收藏

    package com.abin.inter.service;

    public interface UserService {
     
     public static enum UserType{
      UserBasic("Basic Information"),
      UserName("Name Of User"),
      UserSex("Sex Of User"),
      UserAge("Age Of User"),
      UserInitialize("Initialize Of User");
      
      private String info;
      private UserType(String _info){
       this.info=_info;
      }
      
      public String getObject(){
       return info;
      }
     };
     
     
     int UserSum(int one,int two,UserType userInfo);
     String Welcome(String username,UserType userInfo);
    }







    package com.abin.inter.serviceImpl;

    import com.abin.inter.service.UserService;

    public class UserServiceImpl implements UserService{
     @Override
     public int UserSum(int one, int two,UserType userInfo) {
      UserType user=UserType.UserInitialize;
      System.out.println("Enum Info:"+user.getObject());
      if(userInfo.equals(UserType.UserAge)){
       System.out.println("UserInfo:"+userInfo);
       return one+two;
      }
      return 0;
     }

     @Override
     public String Welcome(String username,UserType userInfo) {
      UserType user=UserType.UserInitialize;
      System.out.println("Enum Info:"+user);
      if(userInfo.equals(UserType.UserName)){
       System.out.println("UserInfo:"+userInfo);
       return "歡迎"+username;
      }
      return "NOT WELCOME";
     }

     @Override
     public String toString() {
      // TODO Auto-generated method stub
      return super.toString();
     }
     
     
    }








    package com.abin.inter.test;

    import com.abin.inter.service.UserService;
    import com.abin.inter.service.UserService.UserType;
    import com.abin.inter.serviceImpl.UserServiceImpl;

    import junit.framework.TestCase;

    public class TestUser extends TestCase{
     
     public void test(){
      UserService service=new UserServiceImpl();
      UserType userInfo=UserType.UserAge;
      int result=service.UserSum(10, 17, userInfo);
      System.out.println("UserSum="+result);
      UserType userInfo1=UserType.UserName;
      String result1=service.Welcome("abin", userInfo1);
      System.out.println("Welcome="+result1);
      
     }
    }





    運行結果:
    Enum Info:Initialize Of User
    UserInfo:UserAge
    UserSum=27
    Enum Info:UserInitialize
    UserInfo:UserName
    Welcome=歡迎abin
    posted @ 2012-03-12 22:29 abin 閱讀(644) | 評論 (0)編輯 收藏

       緩存是介于應用程序和物理數據源之間,其作用是為了降低應用程序對物理數據源訪問的頻次,從而提高了應用的運行性能。緩存內的數據是對物理數據源中的數據的復制,應用程序在運行時從緩存讀寫數據,在特定的時刻或事件會同步緩存和物理數據源的數據。

      緩存的介質一般是內存,所以讀寫速度很快。但如果緩存中存放的數據量非常大時,也會用硬盤作為緩存介質。緩存的實現不僅僅要考慮存儲的介質,還要考慮到管理緩存的并發訪問和緩存數據的生命周期。

      Hibernate的緩存包括Session的緩存和SessionFactory的緩存,其中SessionFactory的緩存又可以分為兩類:內置緩存和外置緩存。Session的緩存是內置的,不能被卸載,也被稱為Hibernate的第一級緩存。SessionFactory的內置緩存和Session的緩存在實現方式上比較相似,前者是SessionFactory對象的一些集合屬性包含的數據,后者是指Session的一些集合屬性包含的數據。SessionFactory的內置緩存中存放了映射元數據和預定義SQL語句,映射元數據是映射文件中數據的拷貝,而預定義SQL語句是在Hibernate初始化階段根據映射元數據推導出來,SessionFactory的內置緩存是只讀的,應用程序不能修改緩存中的映射元數據和預定義SQL語句,因此SessionFactory不需要進行內置緩存與映射文件的同步。SessionFactory的外置緩存是一個可配置的插件。在默認情況下,SessionFactory不會啟用這個插件。外置緩存的數據是數據庫數據的拷貝,外置緩存的介質可以是內存或者硬盤。SessionFactory的外置緩存也被稱為Hibernate的第二級緩存。

      Hibernate的這兩級緩存都位于持久化層,存放的都是數據庫數據的拷貝,那么它們之間的區別是什么呢?為了理解二者的區別,需要深入理解持久化層的緩存的兩個特性:緩存的范圍和緩存的并發訪問策略。

      持久化層的緩存的范圍

      緩存的范圍決定了緩存的生命周期以及可以被誰訪問。緩存的范圍分為三類。

      1 事務范圍:緩存只能被當前事務訪問。緩存的生命周期依賴于事務的生命周期,當事務結束時,緩存也就結束生命周期。在此范圍下,緩存的介質是內存。事務可以是數據庫事務或者應用事務,每個事務都有獨自的緩存,緩存內的數據通常采用相互關聯的的對象形式。

      2 進程范圍:緩存被進程內的所有事務共享。這些事務有可能是并發訪問緩存,因此必須對緩存采取必要的事務隔離機制。緩存的生命周期依賴于進程的生命周期,進程結束時,緩存也就結束了生命周期。進程范圍的緩存可能會存放大量的數據,所以存放的介質可以是內存或硬盤。緩存內的數據既可以是相互關聯的對象形式也可以是對象的松散數據形式。松散的對象數據形式有點類似于對象的序列化數據,但是對象分解為松散的算法比對象序列化的算法要求更快。

      3 集群范圍:在集群環境中,緩存被一個機器或者多個機器的進程共享。緩存中的數據被復制到集群環境中的每個進程節點,進程間通過遠程通信來保證緩存中的數據的一致性,緩存中的數據通常采用對象的松散數據形式。

      對大多數應用來說,應該慎重地考慮是否需要使用集群范圍的緩存,因為訪問的速度不一定會比直接訪問數據庫數據的速度快多少。

      持久化層可以提供多種范圍的緩存。如果在事務范圍的緩存中沒有查到相應的數據,還可以到進程范圍或集群范圍的緩存內查詢,如果還是沒有查到,那么只有到數據庫中查詢。事務范圍的緩存是持久化層的第一級緩存,通常它是必需的;進程范圍或集群范圍的緩存是持久化層的第二級緩存,通常是可選的。

      持久化層的緩存的并發訪問策略

      當多個并發的事務同時訪問持久化層的緩存的相同數據時,會引起并發問題,必須采用必要的事務隔離措施。

      在進程范圍或集群范圍的緩存,即第二級緩存,會出現并發問題。因此可以設定以下四種類型的并發訪問策略,每一種策略對應一種事務隔離級別。

      事務型:僅僅在受管理環境中適用。它提供了Repeatable Read事務隔離級別。對于經常被讀但很少修改的數據,可以采用這種隔離類型,因為它可以防止臟讀和不可重復讀這類的并發問題。

      讀寫型:提供了Read Committed事務隔離級別。僅僅在非集群的環境中適用。對于經常被讀但很少修改的數據,可以采用這種隔離類型,因為它可以防止臟讀這類的并發問題。

      非嚴格讀寫型:不保證緩存與數據庫中數據的一致性。如果存在兩個事務同時訪問緩存中相同數據的可能,必須為該數據配置一個很短的數據過期時間,從而盡量避免臟讀。對于極少被修改,并且允許偶爾臟讀的數據,可以采用這種并發訪問策略。   只讀型:對于從來不會修改的數據,如參考數據,可以使用這種并發訪問策略。

      事務型并發訪問策略是事務隔離級別最高,只讀型的隔離級別最低。事務隔離級別越高,并發性能就越低。

      什么樣的數據適合存放到第二級緩存中?

      1、很少被修改的數據

      2、不是很重要的數據,允許出現偶爾并發的數據

      3、不會被并發訪問的數據

      4、參考數據

      不適合存放到第二級緩存的數據?

      1、經常被修改的數據

      2、財務數據,絕對不允許出現并發

      3、與其他應用共享的數據。

      Hibernate的二級緩存

      如前所述,Hibernate提供了兩級緩存,第一級是Session的緩存。由于Session對象的生命周期通常對應一個數據庫事務或者一個應用事務,因此它的緩存是事務范圍的緩存。第一級緩存是必需的,不允許而且事實上也無法比卸除。在第一級緩存中,持久化類的每個實例都具有唯一的OID。

      第二級緩存是一個可插拔的的緩存插件,它是由SessionFactory負責管理。由于SessionFactory對象的生命周期和應用程序的整個過程對應,因此第二級緩存是進程范圍或者集群范圍的緩存。這個緩存中存放的對象的松散數據。第二級對象有可能出現并發問題,因此需要采用適當的并發訪問策略,該策略為被緩存的數據提供了事務隔離級別。緩存適配器用于把具體的緩存實現軟件與Hibernate集成。第二級緩存是可選的,可以在每個類或每個集合的粒度上配置第二級緩存。

      Hibernate的二級緩存策略的一般過程如下:

      1) 條件查詢的時候,總是發出一條select * from table_name where …. (選擇所有字段)這樣的SQL語句查詢數據庫,一次獲得所有的數據對象。

      2) 把獲得的所有數據對象根據ID放入到第二級緩存中。

      3) 當Hibernate根據ID訪問數據對象的時候,首先從Session一級緩存中查;查不到,如果配置了二級緩存,那么從二級緩存中查;查不到,再查詢數據庫,把結果按照ID放入到緩存。

      4) 刪除、更新、增加數據的時候,同時更新緩存。

      Hibernate的二級緩存策略,是針對于ID查詢的緩存策略,對于條件查詢則毫無作用。為此,Hibernate提供了針對條件查詢的Query緩存。

      Hibernate的Query緩存策略的過程如下:

      1) Hibernate首先根據這些信息組成一個Query Key,Query Key包括條件查詢的請求一般信息:SQL, SQL需要的參數,記錄范圍(起始位置rowStart,最大記錄個數maxRows),等。

      2) Hibernate根據這個Query Key到Query緩存中查找對應的結果列表。如果存在,那么返回這個結果列表;如果不存在,查詢數據庫,獲取結果列表,把整個結果列表根據Query Key放入到Query緩存中。

      3) Query Key中的SQL涉及到一些表名,如果這些表的任何數據發生修改、刪除、增加等操作,這些相關的Query Key都要從緩存中清空。

    posted @ 2012-03-11 22:25 abin 閱讀(492) | 評論 (0)編輯 收藏

    來源:http://www.tianxiaboke.com/u/lyeerwy

    級聯保存和更新
    當Hibernate持久化一個臨時對象時,在默認情下,他不會自動持久化所關聯的其他臨時對象,如果希望當持久化對象時把他所關聯的所有臨時對象進行持久化的話:可以把 的cascade屬性設置為"save-update" ,cascade的默認屬性值為none。
    cascade:設置操作對象時的級聯操作,即層級之間的連鎖操作
    值 save-update :表示當保存和更新當前對象(即insert和update語句時),會級聯保存和更新與他關聯的對象
    值 all :表示任何情況下都會進行級聯操作,即對一個對象進行操作,也會對和他關聯的其他對象進行同樣的操作
    值 delete :表示在執行delete時,進行級聯操作,刪除和他關聯的對象
    值 none :表示任何情況下,都不會進行級聯操作
    <set>元素的inverse屬性

    在運行上面的程序時,如果hibernate的"show-sql"設置為true時,就會看到Hibernate會生成很多sql語句,其實很多sql語句都是重復的
    eg: 
    insert into  test.order(o_name,c_id)values(?,?)
    insert into  test.order(o_name,c_id)values(?,?)
    insert into  test order   set c_id=? where id=?
    insert into  test order   set c_id=? where id=?

    為了解決這個問題,我們可以利用在<set>標簽中加上inverse屬性。術語:inverse是指反轉的意思,在 Hibernate中,表示關聯關系中的方向關聯關系中,inverse="false"的主控方,由主動方負責維護對象關系我們 在customer對象的對象配置文件中加上

    <set name="orders"  cascade="save-update" inverse="true">
    <key  column="c_id" > </key>
    <one-to-many class="net.mbs.mypack.Order " />
    </set>

    聲明在Customer和Order的雙向關聯關系中,Customer端的關聯只是Order端關聯的鏡象(即Order端是主空端,負責維護 Customer和order對象之間的關聯關系),當hibernate探測到持久化對象Customer或Order的狀態發生變化時(主要是關聯關系的改變),僅按照Order對象的狀態的變化來同步更新數據庫。
    按次配置,如果在程序中,我們僅僅使用Customer.getOrder().add(order)(涉及了和Order的關聯關系的改變),是不能讓數據庫跟對象的變化來進行數據庫同步更新的,只有利用Order對象的方法改變的Order對象狀態 (eg:order.setCustomer(customer)----涉及到了和Customer的關聯關系的改變)時,數據庫才會根據變化來同步更新數據庫,即只有主控方的狀態(涉及到了和另一方面的關聯關系的改變)發生了變化后,才會觸發對象和數據庫的同步更新。

    映射一對多雙向關聯關系
    當類與類之間建立了關聯,就可以方便的從一個對象導航到另一個對象或一組與他關聯的對象當中,根據上面的程序,對于一個給定的Order對象,如果想獲取與他關聯的Customer對象,我們只需要調用入下方法:
    Customer c=order.geCustomer(); 那么當我們得到一個Customer對象后,想查出和這個Customer對象關聯的所有Order對象時,應該怎么辦呢?由于在Customer中沒有建立對Order對象的關聯,所以,不能通過加載Customer對象來自動加載和他關聯的所有Order對象,唯一的方法只能通過JDBC或SQL語言人工寫出代碼來查詢數據庫Order表來返回所需要的信息
    上面的問題雖然解決,但不能算是最好,因為這樣性能會有所下降,對象位于內存中,在內存中從一個對象導航到另一個對象顯然比到數據庫中查詢數據要快得多

    具體實現<br>
    1:由于Customer和Order是一對多,即一個Customer要對應多個Order,所以在Customer中應該建立一個Set對象,用于存放和本Customer對象關聯的所有Order對象。
    2:在customer.hbm.xml通過<one-to-many>建立對Order表的關聯關系
    注意:<one-to-many>應該放置在<set>標簽中 
    我們先來看看Customer類的設計和customer.hbm.xml文件的內容
    <br><br><br>------------------------------------------------------
    Customer Order 雙向一對多
    1:Customer類中建立一個容器對象,包含關聯的所有Order對象
    2:Order類中建立一個Customer對象,關聯Customer
    inverse="true"表示將維護關聯的權利交給引起Hibernate語句的生成

    customer.getOrders().add(order);
    customer.setName("dddddd");

    inverse="true"(設置此屬性的一方----是被控方)
    當主控方修改對象之間的關聯關系時,讓Hibernate生成sql語句

    posted @ 2012-03-11 16:36 abin 閱讀(1150) | 評論 (0)編輯 收藏

      5個最常問的幾個Hibernate面試問題,不一定你都能回答:

    1.實體對象在Hibernate中如何進行狀態遷移?
    2.何謂Hibernate的N+1問題,如何解決?
    3.Hibernate延遲加載的機制是什么,如何工作?
    4.Hibernate級聯保存要如何做?
    5.Hibernate的二級緩存和一級緩存有什么區別?
    posted @ 2012-03-11 15:34 abin 閱讀(602) | 評論 (0)編輯 收藏

    延遲加載:

       延遲加載機制是為了避免一些無謂的性能開銷而提出來的,所謂延遲加載就是當在真正需要數據的時候,才真正執行數據加載操作。在Hibernate中提供了對實體對象的延遲加載以及對集合的延遲加載,另外在Hibernate3中還提供了對屬性的延遲加載。下面我們就分別介紹這些種類的延遲加載的細節。

    A、實體對象的延遲加載:

    如果想對實體對象使用延遲加載,必須要在實體的映射配置文件中進行相應的配置,如下所示:

    <hibernate-mapping>

    <class name=”com.neusoft.entity.User” table=”user” lazy=”true”>

        ……

    </class>

    </hibernate-mapping>

    通過將class的lazy屬性設置為true,來開啟實體的延遲加載特性。如果我們運行下面的代碼:

    User user=(User)session.load(User.class,”1”);(1)

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

    當運行到(1)處時,Hibernate并沒有發起對數據的查詢,如果我們此時通過一些調試工具(比如JBuilder2005的Debug工具),觀察此時user對象的內存快照,我們會驚奇的發現,此時返回的可能是User$EnhancerByCGLIB$$bede8986類型的對象,而且其屬性為 null,這是怎么回事?還記得前面我曾講過session.load()方法,會返回實體對象的代理類對象,這里所返回的對象類型就是User對象的代理類對象。在Hibernate中通過使用CGLIB,來實現動態構造一個目標對象的代理類對象,并且在代理類對象中包含目標對象的所有屬性和方法,而且所有屬性均被賦值為null。通過調試器顯示的內存快照,我們可以看出此時真正的User對象,是包含在代理對象的 CGLIB$CALBACK_0.target屬性中,當代碼運行到(2)處時,此時調用user.getName()方法,這時通過CGLIB賦予的回調機制,實際上調用CGLIB$CALBACK_0.getName()方法,當調用該方法時,Hibernate會首先檢查 CGLIB$CALBACK_0.target屬性是否為null,如果不為空,則調用目標對象的getName方法,如果為空,則會發起數據庫查詢,生成類似這樣的SQL語句:select * from user where id=’1’;來查詢數據,并構造目標對象,并且將它賦值到CGLIB$CALBACK_0.target屬性中。

        這樣,通過一個中間代理對象,Hibernate實現了實體的延遲加載,只有當用戶真正發起獲得實體對象屬性的動作時,才真正會發起數據庫查詢操作。所以實體的延遲加載是用通過中間代理類完成的,所以只有session.load()方法才會利用實體延遲加載,因為只有session.load()方法才會返回實體類的代理類對象。

    B、        集合類型的延遲加載:

    在Hibernate的延遲加載機制中,針對集合類型的應用,意義是最為重大的,因為這有可能使性能得到大幅度的提高,為此Hibernate進行了大量的努力,其中包括對JDK Collection的獨立實現,我們在一對多關聯中,定義的用來容納關聯對象的Set集合,并不是java.util.Set類型或其子類型,而是 net.sf.hibernate.collection.Set類型,通過使用自定義集合類的實現,Hibernate實現了集合類型的延遲加載。為了對集合類型使用延遲加載,我們必須如下配置我們的實體類的關于關聯的部分:

    <hibernate-mapping>

        <class name=”com.neusoft.entity.User” table=”user”>

    …..

    <set name=”addresses” table=”address” lazy=”true” inverse=”true”>

    <key column=”user_id”/>

    <one-to-many class=”com.neusoft.entity.Arrderss”/>

    </set>

        </class>

    </hibernate-mapping>

    通過將<set>元素的lazy屬性設置為true來開啟集合類型的延遲加載特性。我們看下面的代碼:

    User user=(User)session.load(User.class,”1”);

    Collection addset=user.getAddresses();       (1)

    Iterator it=addset.iterator();                (2)

    while(it.hasNext()){

    Address address=(Address)it.next();

    System.out.println(address.getAddress());

    }

    當程序執行到(1)處時,這時并不會發起對關聯數據的查詢來加載關聯數據,只有運行到(2)處時,真正的數據讀取操作才會開始,這時Hibernate會根據緩存中符合條件的數據索引,來查找符合條件的實體對象。

    這里我們引入了一個全新的概念——數據索引,下面我們首先將接一下什么是數據索引。在Hibernate中對集合類型進行緩存時,是分兩部分進行緩存的,首先緩存集合中所有實體的id列表,然后緩存實體對象,這些實體對象的id列表,就是所謂的數據索引。當查找數據索引時,如果沒有找到對應的數據索引,這時就會一條select SQL的執行,獲得符合條件的數據,并構造實體對象集合和數據索引,然后返回實體對象的集合,并且將實體對象和數據索引納入Hibernate的緩存之中。另一方面,如果找到對應的數據索引,則從數據索引中取出id列表,然后根據id在緩存中查找對應的實體,如果找到就從緩存中返回,如果沒有找到,在發起select SQL查詢。在這里我們看出了另外一個問題,這個問題可能會對性能產生影響,這就是集合類型的緩存策略。如果我們如下配置集合類型:

    <hibernate-mapping>

        <class name=”com.neusoft.entity.User” table=”user”>

    …..

    <set name=”addresses” table=”address” lazy=”true” inverse=”true”>

    <cache usage=”read-only”/>

    <key column=”user_id”/>

    <one-to-many class=”com.neusoft.entity.Arrderss”/>

    </set>

        </class>

    </hibernate-mapping>

    這里我們應用了<cache usage=”read-only”/>配置,如果采用這種策略來配置集合類型,Hibernate將只會對數據索引進行緩存,而不會對集合中的實體對象進行緩存。如上配置我們運行下面的代碼:

    User user=(User)session.load(User.class,”1”);

    Collection addset=user.getAddresses();      

    Iterator it=addset.iterator();               

    while(it.hasNext()){

    Address address=(Address)it.next();

    System.out.println(address.getAddress());

    }

    System.out.println(“Second query……”);

    User user2=(User)session.load(User.class,”1”);

    Collection it2=user2.getAddresses();

    while(it2.hasNext()){

    Address address2=(Address)it2.next();

    System.out.println(address2.getAddress());

    }

    運行這段代碼,會得到類似下面的輸出:

    Select * from user where id=’1’;

    Select * from address where user_id=’1’;

    Tianjin

    Dalian

    Second query……

    Select * from address where id=’1’;

    Select * from address where id=’2’;

    Tianjin

    Dalian

    我們看到,當第二次執行查詢時,執行了兩條對address表的查詢操作,為什么會這樣?這是因為當第一次加載實體后,根據集合類型緩存策略的配置,只對集合數據索引進行了緩存,而并沒有對集合中的實體對象進行緩存,所以在第二次再次加載實體時,Hibernate找到了對應實體的數據索引,但是根據數據索引,卻無法在緩存中找到對應的實體,所以Hibernate根據找到的數據索引發起了兩條select SQL的查詢操作,這里造成了對性能的浪費,怎樣才能避免這種情況呢?我們必須對集合類型中的實體也指定緩存策略,所以我們要如下對集合類型進行配置:

    <hibernate-mapping>

        <class name=”com.neusoft.entity.User” table=”user”>

    …..

    <set name=”addresses” table=”address” lazy=”true” inverse=”true”>

    <cache usage=”read-write”/>

    <key column=”user_id”/>

    <one-to-many class=”com.neusoft.entity.Arrderss”/>

    </set>

        </class>

    </hibernate-mapping>

    此時Hibernate會對集合類型中的實體也進行緩存,如果根據這個配置再次運行上面的代碼,將會得到類似如下的輸出:

    Select * from user where id=’1’;

    Select * from address where user_id=’1’;

    Tianjin

    Dalian

    Second query……

    Tianjin

    Dalian

    這時將不會再有根據數據索引進行查詢的SQL語句,因為此時可以直接從緩存中獲得集合類型中存放的實體對象。

    C、       屬性延遲加載:

       在Hibernate3中,引入了一種新的特性——屬性的延遲加載,這個機制又為獲取高性能查詢提供了有力的工具。在前面我們講大數據對象讀取時,在 User對象中有一個resume字段,該字段是一個java.sql.Clob類型,包含了用戶的簡歷信息,當我們加載該對象時,我們不得不每一次都要加載這個字段,而不論我們是否真的需要它,而且這種大數據對象的讀取本身會帶來很大的性能開銷。在Hibernate2中,我們只有通過我們前面講過的面性能的粒度細分,來分解User類,來解決這個問題(請參照那一節的論述),但是在Hibernate3中,我們可以通過屬性延遲加載機制,來使我們獲得只有當我們真正需要操作這個字段時,才去讀取這個字段數據的能力,為此我們必須如下配置我們的實體類:

    <hibernate-mapping>

    <class name=”com.neusoft.entity.User” table=”user”>

    ……

    <property name=”resume” type=”java.sql.Clob” column=”resume” lazy=”true”/>

        </class>

    </hibernate-mapping>

    通過對<property>元素的lazy屬性設置true來開啟屬性的延遲加載,在Hibernate3中為了實現屬性的延遲加載,使用了類增強器來對實體類的Class文件進行強化處理,通過增強器的增強,將CGLIB的回調機制邏輯,加入實體類,這里我們可以看出屬性的延遲加載,還是通過 CGLIB來實現的。CGLIB是Apache的一個開源工程,這個類庫可以操縱java類的字節碼,根據字節碼來動態構造符合要求的類對象。根據上面的配置我們運行下面的代碼:

    String sql=”from User user where user.name=’zx’ ”;

    Query query=session.createQuery(sql);    (1)

    List list=query.list();

    for(int i=0;i<list.size();i++){

    User user=(User)list.get(i);

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

    System.out.println(user.getResume());    (2)

    }

    當執行到(1)處時,會生成類似如下的SQL語句:

    Select id,age,name from user where name=’zx’;

    這時Hibernate會檢索User實體中所有非延遲加載屬性對應的字段數據,當執行到(2)處時,會生成類似如下的SQL語句:

    Select resume from user where id=’1’;

    這時會發起對resume字段數據真正的讀取操作。

    posted @ 2012-03-11 15:32 abin 閱讀(415) | 評論 (0)編輯 收藏

    讓Spring架構減化事務配置
    注:原創文章,本文曾發表于it168
    Spring顛覆了以前的編程模式,引入了IOC等全新的概念,廣受大家的喜愛。目前大多數j2ee項目都已經采用Spring框架。Spring最大的問題是太多的配置文件,使得你不僅需要維護程序代碼,還需要額外去維護相關的配置文件。最典型的就是事務配置(注:這里的“事務配置”都指“聲明式事務配置”),在Spring中進行事務配置除了定義對象自身的bean外,還需要定義一個進行事務代理的bean.如果你有n個類需要引入事務,那么你就必須定義2n個bean。維護這些bean的代價是十分昂貴的,所以必須要對事務配置進行減化。如果你是基于Spring進行架構設計,那么作為一個好的架構設計師,應該把一些公共的方面進行簡化,讓項目的開發人員只關心項目的業務邏輯,而不要花費太多的精力去關心業務邏輯之外的太多東西。所以作為一個好的架構就應該把事務管理進行簡化,讓程序員花在編程之外的工作最小化。
    1. Spring聲明式事務配置的幾種方法
    在Spring中進行事務控制首先要選擇適當的事務管理器,其次為程序選擇劃分事務的策略。如果只有單個事務性資源,可以從“單一資源”的PlatformTransactionManger實現當中選擇一個,這些實現有:DataSourceTransactionManager,HibernateTransactionManager, JdoTransactionManager,PersistenceBrokerTransactionManager和JmsTransactionManager。根據你所采用的數據庫持久化技術選擇。如果你的項目運行于支持JTA的服務器,那么將選擇JtaTransactionManger,將會支持多資源事務。
    下表將為你選擇適當的事務管理器提供參考。
    技術 事務管理器 內建的事務支持
    JDBC DataSurceTransactionManagerJtaTransactionManager JdbcTemplate和org.springframework.jdbc.object包中的所有類
    IBATIS DataSourceTransactionManagerJtaTransactionManager SqlMapClientTemplate和SqlClientTemplate
    Hibernate HibernateTransactionManagerJtaTransactionManager HibernateTemplate和HibernateInterceptor
    JDO JdoTransactionManagerJtaTransactionManager JdoTemplate和JdoInterceptor
    ApacheOJB PersistenceBrokerTransactionManagerJtaTransactionManager PersistenceBrokerTemplate
    JMS JmsTransactionManager JmsTemplate

    在劃分事務時,我們需要進行事務定義,也就是配置事務的屬性。事務的屬性有傳播行業,隔離級別,超時值及只讀標志。TransactionAttribute接口指定哪些異常將導致一個回滾,哪些應該一次性提交。

    (1) 使用ProxyFactoryBean 和TransactionInterceptor

    <!--定義本地數據源-->

    <bean id="dataSource" name="dataSource" class="org.apache.commons.dbcp.BasicDataSource"           destroy-method="close">
    <property name="driverClassName" value="${jdbc.driverClassName}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
    </bean>


    <!-- !定義單個jdbc數據源的事務管理器-->
    <bean id="transactionManager"               class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
    </bean>

       <!—定義攔截器-->
    <bean id="transactionInterceptor"
          class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <property name="transactionManager">
        <ref bean="transactionManager"/>
        </property>
            <property name="transactionAttributes">
                <props>
                    <prop key="insert*">PROPAGATION_REQUIRED</prop>
                    <prop key="update*">PROPAGATION_REQUIRED</prop>
                    <prop key="save*">PROPAGATION_REQUIRED</prop>
                    <prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop>
                    <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
                    <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
                </props>
            </property>
        </bean>

    <!—定義業務對象-->
    <bean id="com.prs.application.ehld.sample.biz.service.sampleService.target"
           class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
    <property name="userInfoDAO"
        ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
    </property>
    </bean>

    <!—定義業務對象的事務代理對象-->
    <bean id="com.prs.application.ehld.sample.biz.service.sampleService" class="org.springframeword.aop.framework.ProxyFacgtoryBean">
    <property name="target"
        ref="com.prs.application.ehld.sample.biz.service.sampleService.target">
    </property>
    <property name="interceptorNames">
        <value>transactionInterceptor</value>
    </property>
    </bean>

    通過ProxyFacgtoryBean和TransactionInterceptor組合使用,可以對事務進行更多的控制。所有需要事務控制的對象可以共享一個transactionInterceptor的事務屬性。

    (2) 使用TransactionProxyFactoryBean

    <!—定義業務對象-->
    <bean id="com.prs.application.ehld.sample.biz.service.sampleService.target"
           class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
    <property name="userInfoDAO"
        ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
    </property>
    </bean>

        <!—定義業務對象的事務代理對象-->
    <bean id="com.prs.application.ehld.sample.biz.service.sampleService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
              abstract="true">
            <property name="transactionManager">
                <ref bean="transactionManager"/>
            </property>
    <property name="target"
              ref="com.prs.application.ehld.sample.biz.service.sampleService.target" />
            <property name="transactionAttributes">
                <props>
                    <prop key="insert*">PROPAGATION_REQUIRED</prop>
                    <prop key="update*">PROPAGATION_REQUIRED</prop>
                    <prop key="save*">PROPAGATION_REQUIRED</prop>
                    <prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop>
                    <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
                    <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
                </props>
            </property>
        </bean>

    使用TransactionProxyFactoryBean需要為每一個代理對象都去定義自己的事務屬性。

    (3) 使用TransactionProxyFactoryBean及abstract屬性來簡化配置
    這種方工也是目前使用得最多的一種聲明式事務配置方法


    <!--事務控制代理抽象定義 -->
    <bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
            abstract="true">
            <property name="transactionManager">
                <ref bean="transactionManager"/>
            </property>
            <property name="transactionAttributes">
                <props>
                    <prop key="insert*">PROPAGATION_REQUIRED</prop>
                    <prop key="update*">PROPAGATION_REQUIRED</prop>
                    <prop key="save*">PROPAGATION_REQUIRED</prop>
                    <prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop>
                    <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
                    <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
                </props>
            </property>
        </bean>

    <!—定義業務對象-->
    <bean id="com.prs.application.ehld.sample.biz.service.sampleService.target"
           class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
    <property name="userInfoDAO"
        ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
    </property>
    </bean>

    <!—定義業務對象的事務代理對象-->
    <bean id="com.prs.application.ehld.sample.biz.service.sampleService" parent="baseTransactionProxy">
    <property name="target"
        ref="com.prs.application.ehld.sample.biz.service.sampleService.target">
    </property>
    </bean>

    使用abstract屬性,可以讓代理對象可以共享一個定義好的事務屬性,使配置簡化。

    (4)使用BeanNameAutoProxyCreator
        <!—定義攔截器-->
    <bean id="transactionInterceptor"
          class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <property name="transactionManager">
        <ref bean="transactionManager"/>
        </property>
            <property name="transactionAttributes">
                <props>
                    <prop key="insert*">PROPAGATION_REQUIRED</prop>
                    <prop key="update*">PROPAGATION_REQUIRED</prop>
                    <prop key="save*">PROPAGATION_REQUIRED</prop>
                    <prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop>
                    <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
                    <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
                </props>
            </property>
        </bean>


    <!—定義bean別名自動代理創建器-->
    <bean id="autoProxyCreator"
       class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="interceptorNames">
           <value>transactionInterceptor</value>
        </property>
        <property name="beanNames">
        <list>
        <idref local="com.prs.application.ehld.sample.biz.service.sampleService"/>
        </list>
        </property>
    </bean>

    <!—定義業務對象-->
    <bean id="com.prs.application.ehld.sample.biz.service.sampleService"
           class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
    <property name="userInfoDAO"
        ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
    </property>
    </bean>

    使用BeanNameAutoProxyCreator可以由框架來提供適當的代理,由一個transactionInterceptor統一定義事務屬性,只需要把需要事務控制的bean加到beannames的列表。
      對于需要大量聲明式事務的bean,BeanNameAutoProxyCreator是十分方便的。減少了代理bean的定義,還可以靈活的決定一個bean是否進行事務控制。


    上面四種方法是在Spring中常見的聲明式事務配置方法,其中使用TransactionProxyFactoryBean及abstract屬性進行配置是最常見的簡化方法。



    http://www.iteye.com/topic/72435












    posted @ 2012-03-04 17:48 abin 閱讀(542) | 評論 (0)編輯 收藏

    一.
    使用TransactionProxyFactoryBean創建事務代理(通常事務代理以Service層為目標bean)
    <bean id="personService" class="com.lin.personServiceImpl">
        <property name="personDao" ref="personDao"/>
    </bean>
    //配置hibernate的事務管理器,使用HibernateTransactionManager類,該類實現了PlatformTransactionManager接口,針對hibernate 持久化連接的特定實現
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    //配置personService bean的事務代理
    <bean id="personServiceProxy"
            class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
                //指定事務管理器
        <property name="transactionManager" ref="transactionManager"/>
                //指定需要生成代理的日標bean
        <property name="persionService" ref="persionService"/>
                //指定事務屬性
        <property name="transactionAttributes"
            <props>
                <prop key="insert*">PROPAGATION_REQUIRED,-MyCheckedException</prop>
                <prop key="update*>PROPAGATION_REQUIRED</prop>
                <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
            </props>
        </property>


    二.使用自動創建代理簡化事務配置
       使用BeanNameAutoProxyCreator 和DefaultAdvisorAutoProxyCreator創建代理時,并不一定是創建事務代理,關鍵在于傳入的攔截器,如果傳入事務攔截器,將可自動生成事務代理.
    //使用jdbc局部事務策略
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    //配置目標bean1,該目標bean將由Bean后處理器自動生成代理
    <bean id="testbean1" class="com.lin.Testbean1Impl">
        <property name="dataSource" ref="dataSource"/>
    </bean
    //配置目標bean2,該目標bean將由Bean后處理器自動生成代理
    <bean id="testbean2" class="com.lin.Testbean2Impl">
        <property name="dataSource" ref="dataSource"/>
    </bean
    //配置事務攔截器bean
    <bean id="transactionInterceptor"
       class="org.springframework.transaction.interceptor.TransactionInterceptor">
            //事務攔截器需要注入一個事務管理器
          <property name="transactionManager" ref="transactionManager"/>
           <property name="transactionAttributes">
                //定義事務傳播屬性
                <props>
                        <prop key="insert*">PROPAGATION_REQUIRED</prop>
                        <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
                        <prop key="*">PROPAGATION_REQUIRED</prop>
                </props>
            </property>
        //定義BeanNameAutoProxyCreator的Bean后處理器
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames">
            <list>
                <value>testbean1</value>
                <value>testbean2</value>
            </list>
                //此處可以增加其他需要創建事務代理的bean
        </property>
            //定義BeanNameAutoProxyCreator所需要的攔截器
         <property name="interceptorNames">
            <list>
                <value>transactionInterceptor</value>
                    //此處可以增加其他新的Interceptor
            </list>
        </property>
    </bean>
    posted @ 2012-03-04 16:37 abin 閱讀(366) | 評論 (0)編輯 收藏

    僅列出標題
    共50頁: First 上一頁 42 43 44 45 46 47 48 49 50 下一頁 
    主站蜘蛛池模板: 中文字幕亚洲专区| 野花香高清在线观看视频播放免费| 久久九九亚洲精品| 国产中文字幕免费观看| 男人的好看免费观看在线视频| 国产精品免费AV片在线观看| 一级免费黄色毛片| 美女一级毛片免费观看| 亚洲综合无码一区二区痴汉 | 欧美亚洲精品一区二区| 亚洲三级视频在线观看| 亚洲嫩草影院久久精品| 亚洲精品蜜桃久久久久久| 免费大黄网站在线观| 色播在线永久免费视频| 青青草免费在线视频| 四虎永久在线观看免费网站网址 | 免费福利视频导航| 久久免费动漫品精老司机 | 日韩亚洲欧洲在线com91tv| 亚洲欧洲久久av| 四虎1515hm免费国产| 国产成人精品高清免费| 日韩免费观看视频| 免费鲁丝片一级在线观看| 在线观看免费为成年视频| 啦啦啦在线免费视频| 成人午夜性A级毛片免费| 在线观看免费成人| 国产高清免费观看| 免费中文字幕不卡视频| 亚洲AV无码之日韩精品| 亚洲成aⅴ人片久青草影院| 亚洲国产人成精品| 久久综合亚洲色HEZYO国产| 国产成人综合亚洲AV第一页| 亚洲人午夜射精精品日韩| 浮力影院亚洲国产第一页| 中国亚洲女人69内射少妇| 久久精品国产69国产精品亚洲| 久久精品国产亚洲AV网站|