首页 > 代码库 > Hibernate-----Hibernate主键生成器

Hibernate-----Hibernate主键生成器

increment

对long、int、short的数据列生成自动增长主键。用于数据库中未把表格主键设置为自增,而又想表格主键自增时


实现机制:在当前应用实例中维持一个变量,以保存着当前的最大值,之后每次需要生成主键的时候将此值加1作为主键 


使用范围:若当前有多个实例访问同一个数据库,由于各个实例各自维护主键状态,不同实例可能生成同样的主键,从而造成主键重复异常。因此,若同一数据库有多个实例(也就是并发量大的)问,此方式必须避免使用。 只有在没有其他进程往同一张表中插入数据时才能使用(在集群下不要使用)。但是它的生成标识符机制不依赖于底层数据库系统,所以他适合于所有的数据库系统


identity
对如SQLServer,MySQL等支持自动增长列的数据库,如果数据列的类型是long、short或int,可使用该主键生成器来生成自动增长主键


使用范围:要求底层数据系统必须支持自动增长字段类型。而且它需要底层数据库把主键定义为自动增长字段类型


native
依据底层数据库对自动生成标识符的支持能力,来选择使用identity、sequence或hilo标识符生成器。能自动判断底层数据库提供的生成标识符的机制
       
使用范围:适合于跨数据库平台开发,即同一个Hibernate应用需要连接多种数据库系统的场合


sequence
对如Oracle,DB2等支持Sequence的数据库,如果数据列的类型是long,short或int,可使用该主键生成器生成自动增长主键。该标识符生成器利用底层数据库提供的序列来生成标识符
<id name="id" column="id">
     <generator class="sequence">
          <!-- 数据库中创建系列userTb_seq -->
          <param name="sequence">userTb_seq</param>
    </generator>
</id>


uuid.hex 
由Hibernate基于128 位唯一值产生算法生成16 进制数值(编码后以长度32 的字符串表示)、作为主键


uuid.string 
与uuid.hex 类似,只是生成的主键未进行编码(长度16)、。在某些数据库中可能出现问题(如PostgreSQL)、


assigned 
主键由外部程序负责生成
<id name="id" column="id">
     <generator class="assigned" />
</id>


hilo
由HIbernate按照一种high/low算法来生成标识符,要在数据库中建立一张额外的表,默认表名(hibernate_unque_key),默认字段(next_hi:integer类型);他从数据库的特定表字段中获取high值;较少用
<id name="id" type="long" column="ID">
         <generator class="hilo">
             <param name="table">hi_value</param>
             <param name="column">next_value</param>
             <param name="max_lo">100</param>
         </generator>
</id>


上例:high值放在hi_value表的next_value字段中
Hibernate 在持久化一个对象时,需要读取并修改hi_value表中的next_value值。这段操作在单独的事务中处理。当save时,不使用当前 session对象的当前数据库联接和事务,而是在一个新的数据库连接中创建新事务,然后访问hi_value表。


适用范围:
适用于所有的数据库系统。
OID必须为long、int或short型,如果定义为byte类型,会抛出异常。
只能在一个数据库中保证标识符唯一
当用户为Hibernate自行提供数据库联接,或者Hibernate通过JTA,从应用服务器的数据源获得数据库联接时无法适用hilo,因为这样不能保证hilo在新的数据库连接的事务中访问hi_value表。在这种情况下,如果数据库系统支持序列,可适用seqhilo生成器。对于支持序列的数据库系统,可适用seqhilo,它从序列中获取high值。
       
一般而言,利用uuid.hex方式生成主键将提供最好的性能和数据库平台适应性。


另外由于常用的数据库,如Oracle、DB2、SQLServer、MySql 等,都提供了易用的主键生成机制(Auto-Increase 字段或者Sequence)。可在数据库提供的主键生成机制上采用generator-class=native的主键生成方式。不过值得注意的是,一些数据库提供的主键生成机制在效率上未必最佳,大量并发insert数据时可能会引起表之间的互锁。数据库提供的主键生成机制,往往是通过在一个内部表中保存当前主键状态(如对于自增型主键而言,此内部表中就维护着当前的最大值和递增量),之后每次插入数据会读取这个最大值,然后加上递增量作为新记录的主键,之后再把这个新的最大值更新回内部表中,这样,一次Insert操作可能导致数据库内部多次表读写操作,同时伴随的还有数据的加锁解锁操作,这对性能产生了较大影响。因此,对于并发Insert要求较高的系统,推荐采用uuid.hex 作为主键生成机制


foregin
表明直接使用另一个关联的对象的标识属性值(即本持久化对象不能生成主键);这种主键生成器只在基于主键的1-1关联映射中才有用


select

通过数据库触发器选择某个唯一主键的行,并返回其主键值作为标识属性值


自定义主键生成器

主键生成器必须实现  net.sf.hibernate.id.IdentifierGenerator  接口
主键生成类MyIdentifierGenerator

 public class MyIncrementGenerator implements IdentifierGenerator, Configurable{    
          private static final Log log = LogFactory.getLog(MyIncrementGenerator.class);
          private long next;
          private String sql;
    
          public synchronized Serializable generate(SessionImplementor session, Object object)
             throws SQLException, HibernateException {
             if (sql!=null) {
            //获得下一个主键的编号,可以自己定义
            getNext(session.connection());
          }
          return String.valueOf(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);
        returnClass = type.getReturnedClass();
        
        sql = "select max(to_number(" + column + ")) from " + ( schema==null ? table : schema + '.' + table );
      }


      private void getNext(Connection conn)throws SQLException {
        PreparedStatement st = conn.prepareStatement(sql);
        ResultSet rs = null;
        try {
            rs = st.executeQuery();
            if ( rs.next()) {
                next = rs.getLong(1) + 1;
                if ( rs.wasNull() ) 
                   next = 1;
            }
            else {    
                next = 1;
            }
            sql=null;
            log.debug("first free id: " + next);
        }
        finally {
            if (rs!=null)
               rs.close();
            st.close();
        }
     }

然后再需要使用自定义的主键生成器构造主键的数据库对象所对应的.XML文件中可以这样写:

<id name="uniqueid" column="UNIQUEID" type="string">
        <generator class="com.core.persistence.MyIncrementGenerator"/>
</id>







Hibernate-----Hibernate主键生成器