Java Blog for Alex Wan

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

          統(tǒng)計

          留言簿(10)

          BlogJava

          Blogs

          DIV+CSS

          JQuery相關

          友情鏈接

          常去的地方

          數(shù)據(jù)供應

          閱讀排行榜

          評論排行榜

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

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

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

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

          實現(xiàn)代碼:
          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實例測試,如發(fā)現(xiàn)有問題,請留言.


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

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

          評論

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

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

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

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

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

          說的很有道理.

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

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

          # 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的實例,同時往一個數(shù)據(jù)表不停的插數(shù)據(jù),數(shù)據(jù)量各為1萬,未出現(xiàn)主鍵不唯一的情況.

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

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

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

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

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

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

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

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

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

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

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

          主站蜘蛛池模板: 游戏| 佳木斯市| 开远市| 读书| 赣州市| 元江| 蕉岭县| 玛纳斯县| 金门县| 陆川县| 潞城市| 抚顺市| 南城县| 来安县| 浦江县| 寿阳县| 北辰区| 拉萨市| 砚山县| 新余市| 鄂尔多斯市| 修水县| 台北县| 德庆县| 乌审旗| 奉节县| 钦州市| 方山县| 家居| 竹溪县| 多伦县| 南昌市| 南部县| 沁水县| 磴口县| 岱山县| 凤山县| 石门县| 云梦县| 万山特区| 历史|