Java Blog for Alex Wan

          Let life be beautiful like summer flowers and death like autumn leaves.

          導航

          <2008年9月>
          31123456
          78910111213
          14151617181920
          21222324252627
          2829301234
          567891011

          隨筆分類(148)

          文章分類

          隨筆檔案(104)

          統計

          留言簿(10)

          BlogJava

          Blogs

          DIV+CSS

          JQuery相關

          友情鏈接

          常去的地方

          數據供應

          閱讀排行榜

          評論排行榜

          [hibernate]hibernate中自定義主鍵生成器

          背景:
          Hibernate(目前使用的版本是3.2)中提供了多種生成主鍵的方式.在下面的文章中有列出來
          [hibernate]Hibernate主鍵生成方式 Key Generator

          然而當前的這么多種生成方式未必能滿足我們的要求.
          比如increment,可以在一個hibernate實例的應用上很方便的時候,但是在集群的時候就不行了.
          再如 identity ,sequence ,native 是數據局提供的主鍵生成方式,往往也不是我們需要,而且在程序跨數據庫方面也體現出不足.
          還有基于算法的生成方式生成出來的主鍵基本都是字符串的.

          我們現在需要一種生成方式:使用Long作為主鍵類型,自動增,支持集群.
          那么我們需要自定義一個我們的主鍵生成器才能實現了.

          實現代碼:
          package hibernate;

          import java.io.Serializable;
          import java.sql.Connection;
          import java.sql.PreparedStatement;
          import java.sql.ResultSet;
          import java.sql.SQLException;
          import java.util.Properties;

          import org.apache.commons.logging.Log;
          import org.apache.commons.logging.LogFactory;
          import org.hibernate.HibernateException;
          import org.hibernate.MappingException;
          import org.hibernate.dialect.Dialect;
          import org.hibernate.engine.SessionImplementor;
          import org.hibernate.id.Configurable;
          import org.hibernate.id.IdentifierGenerator;
          import org.hibernate.id.PersistentIdentifierGenerator;
          import org.hibernate.type.Type;


          public class IncrementGenerator implements IdentifierGenerator, Configurable {
              
          private static final Log log = LogFactory.getLog(IncrementGenerator.class);
              
          private Long next;
              
          private String sql;
              
          public Serializable generate(SessionImplementor session, Object object)
                      
          throws HibernateException {
                  
          if (sql!=null{
                      getNext( session.connection() );
                  }

                 
          return next;

              }

              
              
          public void configure(Type type, Properties params, Dialect d) throws MappingException {
                  String table 
          = params.getProperty("table");
                  
          if (table==null) table = params.getProperty(PersistentIdentifierGenerator.TABLE);
                  String column 
          = params.getProperty("column");
                  
          if (column==null) column = params.getProperty(PersistentIdentifierGenerator.PK);
                  String schema 
          = params.getProperty(PersistentIdentifierGenerator.SCHEMA);
                  sql 
          = "select max("+column +") from " + ( schema==null ? table : schema + '.' + table );
                  log.info(sql);
              }

              
               
          private void getNext(Connection conn) throws HibernateException {
                      
          try {
                          PreparedStatement st 
          = conn.prepareStatement(sql);
                          ResultSet rs 
          = st.executeQuery();
                          
          if ( rs.next() ) {
                              next 
          = rs.getLong(1+ 1;
                          }

                          
          else {
                              next 
          = 1l;
                          }

                      }
          catch(SQLException e)
                      
          {
                          
          throw new HibernateException(e);
                      }

                      
          finally {
                          
          try{
                          conn.close();
                          }
          catch(SQLException e)
                          
          {
                              
          throw new HibernateException(e);
                          }

                      }

                  }

          }



          配置:
          在對應的hbm文件里面將id的配置如下:
                  <id name="id" type="long" column="id" >
                      
          <generator class="hibernate.IncrementGenerator" /> 
                  
          </id>

          ps:此生成方式僅通過兩個hibernate實例測試,如發現有問題,請留言.


          Let life be beautiful like summer flowers and death like autumn leaves.

          posted on 2008-09-02 11:59 Alexwan 閱讀(3929) 評論(8)  編輯  收藏 所屬分類: J2EE數據庫

          評論

          # re: [hibernate]hibernate中自定義主鍵生成器 2008-09-02 13:25 隔葉黃鶯

          如果當前某個表的ID值是2,某一個實例用這個自定義主鍵生成器得到主鍵是3,但還未插入記錄,這時另一Hibernate實例拿到的主鍵也是3,并執行完 insert 操作后,第一個實例執行 insert 操作。

          像這種情況不知如何保證主鍵的唯一性

          我覺得直接用數據庫來產生主鍵是能保證唯一性的,如果自己程序在有 Hibernate 多實例時確保產生的主鍵唯,也須要加上同步,是否可以把這個同步放到數據庫這一層去,讓程序更簡單。  回復  更多評論   

          # re: [hibernate]hibernate中自定義主鍵生成器 2008-09-02 14:23 Alexwan

          說的很有道理.

          另外一個問題凸顯出來了,就是hibernate是在插入數據前去獲取主鍵的,如果是這樣無論用什么辦法去做都是有機會導致主鍵不唯一啊(多hibernate實例的情況下),只是視乎幾率的大小而已.

          如果將生成主鍵的工作放到數據庫這一層,那么在插入之前hibernate是不知道主鍵是多少的,這樣的話,我又如何去獲取我剛剛插入那條數據呢?有的時候需要返回新的記錄對象.  回復  更多評論   

          # re: [hibernate]hibernate中自定義主鍵生成器 2008-09-02 14:32 隔葉黃鶯

          看看 Hibernate 的 session.save() 操作,它返回的就是一個主鍵,從源代碼就知道,它是首先取得主鍵,然后再 insert ........
          而不是通常像我們那樣(比如說在 Oracle)insert into ...... values(oneSeq.nextval.....  回復  更多評論   

          # re: [hibernate]hibernate中自定義主鍵生成器 2008-09-02 15:45 Alexwan

          剛用這個主鍵生成配置后,用兩臺機器各自運行一個hibernate的實例,同時往一個數據表不停的插數據,數據量各為1萬,未出現主鍵不唯一的情況.

          可以放心使用了!  回復  更多評論   

          # re: [hibernate]hibernate中自定義主鍵生成器 2008-09-02 16:06 隔葉黃鶯

          測試代碼中業務邏輯要體現出來,比如兩個長短不一樣的邏輯(通常是有的,針對用戶的輸入可能復雜度不一樣的),長邏輯的實例先拿到主鍵(2),這時短邏輯的實例進來也拿到主鍵(2),然后很快 insert 了記錄,而長邏輯的實例之后才執行 insert,這種情況也就出問題了。

          再者,把 Hibernate 實例換成了多線程環境中的線程,即使不是在集群環境下也是會出問題的。  回復  更多評論   

          # re: [hibernate]hibernate中自定義主鍵生成器 2008-09-02 16:59 Alexwan

          從事務的角度來看確實會有問題.

          那這樣的話,您認為如果要在集群的環境下保持主鍵唯一,使用什么方式要一點呢?有沒有這方面的經驗呢?  回復  更多評論   

          # re: [hibernate]hibernate中自定義主鍵生成器 2008-09-02 17:20 隔葉黃鶯

          當然還是數據庫,產生主鍵的機制設置為 Native,數據庫方言也會選擇正確的數據庫對象來產生主鍵,如 Oracle 的序列,Db2 的 indentity,某些數據庫的自增字段。  回復  更多評論   

          # re: [hibernate]hibernate中自定義主鍵生成器 2008-09-02 17:38 Alexwan

          OK,謝謝指教  回復  更多評論   

          主站蜘蛛池模板: 马尔康县| 商水县| 全南县| 白银市| 金昌市| 河池市| 扎兰屯市| 得荣县| 司法| 阿荣旗| 固安县| 姜堰市| 南汇区| 临江市| 阿合奇县| 邯郸市| 丁青县| 奎屯市| 肇庆市| 宝丰县| 大丰市| 潞城市| 石渠县| 如皋市| 巴青县| 夏津县| 平顺县| 桃江县| 扶余县| 荥阳市| 大竹县| 邳州市| 新龙县| 板桥市| 准格尔旗| 金华市| 永丰县| 南漳县| 陆良县| 彰化市| 阿图什市|