首页 > 其他分享 >hibernate中自定义主键生成器

hibernate中自定义主键生成器

时间:2023-06-04 14:34:07浏览次数:38  
标签:hibernate String 自定义 生成器 id org import 主键


自定义 hibernate 主键生成机制 [url]http://walle1027.iteye.com/blog/1114824[/url]
org.hibernate.id.MultipleHiLoPerTableGenerator主键生成器
[url]http://suzefeng8806.iteye.com/blog/923511[/url]
[url]http://zhongrf.iteye.com/blog/972303[/url]

[b][color=red]生成器@ TableGenerator[/color][/b]
[url]http://zpfadmin.iteye.com/blog/670319[/url]
将当前主键的值单独保存到一个数据库的表中,主键的值每次都是从指定的表中查询来获得,这种生成主键的方式也是很常用的。这种方法生成主键的策略可以适用于任何的数据库,不必担心不同数据库不兼容造成的问题。
使用以下SQL脚本创建一个表“tb_generator”,并插入两条数据,SQL脚本如下所示。

CREATE TABLE  tb_generator (
  id int(20) unsigned NOT NULL auto_increment,
  gen_name varchar(255) NOT NULL,
  gen_value int(20) NOT NULL,
  PRIMARY KEY  (id)
)
INSERT INTO tb_generator ( gen_name ,gen_value ) VALUES ( 'CUSTOMER_PK',1);
INSERT INTO tb_generator ( gen_name ,gen_value ) VALUES ( 'CONTACT_PK',100);


执行SQL语句后,表中的数据如图5.1所示。



图5.1 自动生成主键表tb_generator


现在有另外两个表customer和contact,它们每次新建记录时生成主键的值分别“CUSTOMER_PK”所对应的value值加 1,“CONTACT_PK”所对应的value值加1。


下面就来具体看一下如何来配置主键的生成策略,以配置“customer”表为例,步骤如下。


[color=darkblue](1)在Entity标记主键的位置[/color],指定主键生成策略为“GenerationType.TABLE”,具体设置如下。


@Entity
@Table(name = "customer")
public final class CustomerEO implements java.io.Serializable {
         private Integer id;
         @Id
         @GeneratedValue(strategy = GenerationType.TABLE)
         public Integer getId() {
                   return this.id;
         }
         public void setId(Integer id) {
                   this.id = id;
         }
}


[color=darkblue](2)指定生成主键策略的名称[/color],例如这里命名为“customer_gen”。


@Id
         @GeneratedValue(strategy = GenerationType.TABLE,generator="customer_gen")
         public Integer getId() {
                   return this.id;
         }


[color=darkblue](3)使用@ TableGenerator标记[/color]定义表生成策略的具体设置,代码如下所示。


@Id
         @GeneratedValue(strategy = GenerationType.TABLE,generator="customer_gen")
         @TableGenerator(name = "customer_gen",
                            table="tb_generator",
                            pkColumnName="gen_name",
                            valueColumnName="gen_value",
                            pkColumnValue="CUSTOMER_PK",
                            allocationSize=1
         )
         public Integer getId() {
                   return this.id;
         }


这样,当通过以下代码创建新的实体后,表tb_generator中“CUSTOMER_PK”的value的值将自动加1,如图5.2所示。


CustomerEO customer = new CustomerEO();
             customer.setName("Janet");
             customer.setShortName("Jane");
             entityManager.persist(customer);



图5.2 添加新数据后表tb_generator


[color=darkblue](4)@TableGenerator标记用于设置主键使用数据表生成主键的策略[/color],它的定义如下所示。


@Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)
public @interface TableGenerator {
String name();
String table() default "";
String catalog() default "";
String schema() default "";
String pkColumnName() default "";
String valueColumnName() default "";
String pkColumnValue() default "";
int initialValue() default 0;
int allocationSize() default 50;
UniqueConstraint[] uniqueConstraints() default {};
}


在使用此@ TableGenerator标记时,需要注意以下几个问题。


l [color=red]该标记可以在类名、方法名、和属性名前。并且一旦在实体中标记,它不仅可以在本实体中使用,在其他的实体中也可以引用。它的作用范围是整个persist unit配置的实体类中[/color]。


例如以上的定义也可以写成:


@Entity
@Table(name = "customer")
@TableGenerator(name = "customer_gen",
                   table="tb_generator",
                   pkColumnName="gen_name",
                   valueColumnName="gen_value",
                   pkColumnValue="CUSTOMER_PK",
                   allocationSize=1
)
public class CustomerEO implements java.io.Serializable {
         ……
}


或者将其标注在ContactEO中,也是可以的。但建议标注在所作用的实体中,这样有助于方便查看。


l [b]name[/b]属性表示该表主键生成策略的名称,它被引用在@GeneratedValue中设置的“generator”值中。


l [b]table[/b]属性表示表生成策略所持久化的表名,例如,这里表使用的是数据库中的“tb_generator”。


l [b]catalog[/b]属性和schema具体指定表所在的目录名或是数据库名。


l [b]pkColumnName[/b]属性的值表示在持久化表中,该主键生成策略所对应键值的名称。例如在“tb_generator”中将“gen_name”作为主键的键值


l [b]valueColumnName[/b]属性的值表示在持久化表中,该主键当前所生成的值,它的值将会随着每次创建累加。例如,在“tb_generator”中将“gen_value”作为主键的值


l [b]pkColumnValue[/b]属性的值表示在持久化表中,该生成策略所对应的主键。例如在“tb_generator”表中,将“gen_name”的值为 “CUSTOMER_PK”。


l [b]initialValue[/b]表示主键初识值,默认为0。


l [b]allocationSize[/b]表示每次主键值增加的大小,例如设置成1,则表示每次创建新记录后自动加1,默认为50。[b][color=red]为了降低标识生成时频繁操作数据库造成 的性能上的影响,实体标识生成的时候会一次性的获取多个实体标识,该属性设置的就是一次性获取实体标识的数目。[/color][/b]该属性并不是必须设置的属性,如果开发者没有为该属性设置值,OpenJPA 容器将会使用默认值 50 。


l [b]UniqueConstraint[/b]与@Table标记中的用法类似,请读者参阅5.2.1小节。


用一个简单示意图表示持久化主键表和表生成策略,如图所示。


hibernate中自定义主键生成器_主键




[color=red][b]hibernate中自定义主键生成器[/b][/color] 原文:[url]http://lin23871.iteye.com/blog/363062[/url]


背景:


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>





另一个主键生成方式的例子


package com.mc.framework.hibernate.id;  

import java.io.Serializable;  
import java.sql.Connection;  
import java.sql.PreparedStatement;  
import java.sql.ResultSet;  
import java.sql.SQLException;  
import java.text.MessageFormat;  
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.IdentifierGeneratorFactory;  
import org.hibernate.id.MultipleHiLoPerTableGenerator;  
import org.hibernate.id.PersistentIdentifierGenerator;  
import org.hibernate.mapping.Table;  
import org.hibernate.type.Type;  
import org.hibernate.util.PropertiesHelper;  
import org.hibernate.util.StringHelper;  

import com.htf.framework.util.ClassUtil;  

public class AutoadjustMultipleHiLoGenerator  
        extends MultipleHiLoPerTableGenerator   
        implements PersistentIdentifierGenerator,Configurable {  

    private static final Log _log = LogFactory.getLog(AutoadjustMultipleHiLoGenerator.class);  

    public static final int DEFAULT_START_VALUE = 0;  
    private static final String START_VALUE = "start_value";  

    public static final int DEFAULT_MAX_LO = 10000;  
    protected int startValue;  
    protected String _query = null;  
    protected String _insert = null;  
    protected String _update = null;  
    protected String _tableName = null;  

    protected int _maxLo;  
    protected long _hi = 0;  
    protected int _lo;  
    protected Class<?> _returnClass;  

    private String selectMaxSQL = null;  

    public Serializable doWorkInCurrentTransaction(Connection conn, String sql)  
            throws SQLException {  

        // 这个结果是高位,保存在数据库中的值.  
        int result = 0;  
        int updateRows = 0;  
        int nextInTable; // 表中ID的最大值  

        do {  
            // SQL.debug(_query);  
            PreparedStatement qps = conn.prepareStatement(_query);  
            PreparedStatement ips = null;  
            try {  
                ResultSet rs = qps.executeQuery();  
                boolean isInitialized = rs.next();  

                // 没有初始化,则代表ID表中,没有该表主键的记录  
                if (!isInitialized) {  
                    nextInTable = this.getNext(conn);  
                    _log.debug("表中记录最大值为的下一个值 : " + nextInTable);  
                    int curVal = nextInTable - 1;// 当前值  
                    if (curVal == 0) {  
                        return 0;  
                    }  

                    int tmp = curVal / (_maxLo + 1);  
                    result = tmp + 1;  

                    ips = conn.prepareStatement(_insert);  
                    ips.setInt(1, result);  
                    ips.execute();  
                } else {  
                    result = rs.getInt(1);  
                }  
                rs.close();  
            } catch (SQLException sqle) {  
                _log.error("could not read or init a hi value", sqle);  
                throw sqle;  
            } finally {  
                if (ips != null) {  
                    ips.close();  
                }  
                qps.close();  
            }  

            // sql = update;  
            PreparedStatement ups = conn.prepareStatement(_update);  
            try {  
                ups.setInt(1, result + 1);// 新值  
                ups.setInt(2, result);// 旧值  
                updateRows = ups.executeUpdate();  
            } catch (SQLException sqle) {  
                _log.error("could not update hi value in: " + _tableName, sqle);  
                throw sqle;  
            } finally {  
                ups.close();  
            }  
        } while (updateRows == 0);  
        return new Integer(result);  
    }  

    public synchronized Serializable generate(SessionImplementor session,  
            Object obj) throws HibernateException {  

        // 低位会不断在内存中加一,如果当低位大于 "最大的低位" 时,  
        //则从数据库中将高位加一,低位归零,再一次循环  
        if (_lo > _maxLo) {  
            // 高位  
            int hival = ((Integer) doWorkInNewTransaction(session)).intValue();  
            _lo = (hival == 0) ? 1 : 0;  
            _hi = hival * (_maxLo + 1);  
            String msg = "高低位生成的ID的信息 : new hiValue=[{0}],maxLo=[{1}],lo=[{2}],hi=[{3}]";  
            _log.debug(MessageFormat.format(msg, hival, _maxLo, _lo, _hi));  
        }  

        Number genedId = IdentifierGeneratorFactory.createNumber(_hi + _lo,  
                _returnClass);  
        _lo++;  

        _log.debug("根据高低位生成的ID为: " + genedId);  
        return genedId;  
    }  

    @Override  
    public void configure(Type type, Properties params, Dialect dialect)  
            throws MappingException {  
        startValue = PropertiesHelper.getInt(START_VALUE, params,  
                DEFAULT_START_VALUE);  

        super.configure(type, params, dialect);  
        _query = ClassUtil.getFieldValue(this, "query", String.class);  
        _insert = ClassUtil.getFieldValue(this, "insert", String.class);  
        _update = ClassUtil.getFieldValue(this, "update", String.class);  
        _tableName = ClassUtil.getFieldValue(this, "tableName", String.class);  

        // _maxLo = ClassUtil.getFieldValue(this, "maxLo", Integer.class);  
        _maxLo = PropertiesHelper.getInt(MAX_LO, params, DEFAULT_MAX_LO);  
        _lo = ClassUtil.getFieldValue(this, "lo", Integer.class);  
        _returnClass = ClassUtil  
                .getFieldValue(this, "returnClass", Class.class);  
        configureForIncrement(type, params, dialect);  
    }  

    private void configureForIncrement(Type type, Properties params,  
            Dialect dialect) {  
        String tableList = params.getProperty("tables");  

        if (tableList == null)  
            tableList = params.getProperty(PersistentIdentifierGenerator.TABLES);  

        String[] tables = StringHelper.split(", ", tableList);  
        String column = params.getProperty("column");  
        if (column == null)  
            column = params.getProperty(PersistentIdentifierGenerator.PK);  
        String schema = params.getProperty(PersistentIdentifierGenerator.SCHEMA);  
        String catalog = params.getProperty(PersistentIdentifierGenerator.CATALOG);  

        StringBuffer buf = new StringBuffer();  
        for (int i = 0; i < tables.length; i++) {  
            if (tables.length > 1) {  
                buf.append("select ").append(column).append(" from ");  
            }  
            buf.append(Table.qualify(catalog, schema, tables[i]));  
            if (i < tables.length - 1)  
                buf.append(" union ");  
        }  
        if (tables.length > 1) {  
            buf.insert(0, "( ").append(" ) ids_");  
            column = "ids_." + column;  
        }  

        selectMaxSQL = "select max(" + column + ") from " + buf.toString();  

    }  

    private int getNext(Connection conn) {  
        long next;  
        PreparedStatement st = null;  
        ResultSet rs = null;  
        try {  
            st = conn.prepareStatement(selectMaxSQL);  
            rs = st.executeQuery();  
            try {  
                if (rs.next()) {  
                    next = rs.getLong(1) + 1;  
                    if (rs.wasNull())  
                        next = 1;  
                } else {  
                    next = 1;  
                }  
                selectMaxSQL = null;  
            } finally {  
                if (rs != null) {  
                    rs.close();  
                }  
                if (st != null) {  
                    st.close();  
                }  
            }  
        } catch (SQLException sqle) {  
            throw new RuntimeException(sqle);  
        }  
        return new Long(next).intValue();  
    }  

}

标签:hibernate,String,自定义,生成器,id,org,import,主键
From: https://blog.51cto.com/u_3871599/6410605

相关文章

  • dubbo源码学习(二) : spring 自定义标签
    做dubbo的配置时很容易发现,dubbo有一套自己的标签,提供给开发者配置,其实每一个标签对应着一个实体,在容器启动的时候,dubbo会对所有的配置进行解析然后将解析后的内容设置到实体里,最终dubbo会根据实体中的值生成贯穿全局的统一URL。利用自定义标签使配置简单明......
  • 在 Spring 中自定义 scope
    大家对于Spring的scope应该都不会默认。所谓scope,字面理解就是“作用域”、“范围”,如果一个bean的scope配置为singleton,则从容器中获取bean返回的对象都是相同的;如果scope配置为prototype,则每次返回的对象都不同。一般情况下,Spring提供的scope都能满足日常应用的......
  • Flex/AS3/flash player支持屏蔽右键菜单,自定义菜单,并设置相应的菜单事件(示例,图解)..
    播放器版本11.2以后支持右键菜单屏蔽及自定义菜单1.更新播放器,11.2以上版本http://download.macromedia.com/get/flashplayer/updaters/11/playerglobal11_3.swchttp://download.macromedia.com/get/flashplayer/updaters/11/playerglobal11_4.swchttp://download.macro......
  • 组件的自定义事件
      专门用来看自定义事件的:  ......
  • svgicon 实现自定义 svg icon
      对于后台管理框架,经常要用到自定义的svg来当做路由的icon图标。https://mmf-fe.github.io/svgicon,这是这款插件的地址。这里总结下在vue3+vite中使用改插件的方式。安装yarnadd@yzfe/svgicon@yzfe/vue3-svgiconyarnaddvite-plugin-svgicon--dev配置vit......
  • 二、JMX自定义MBean
    一、自定义MBeanpublicinterfaceHelloMBean{StringgetName();voidsetName(Stringname);Stringprint();}HelloMBean必须以MBean结尾。@Slf4jpublicclassHelloimplementsHelloMBean{privateStringname;@OverridepublicSt......
  • Android 自定义View 之 饼状进度条
    饼状进度条前言正文一、XML样式二、构造方法三、测量四、绘制①绘制描边①绘制进度五、API方法六、使用七、源码前言  前面写了圆环进度条,这次我们来写一个饼状进度条,首先看一下效果图:正文  效果图感觉怎么样呢?下面我们来实现这个自定义View,依然是写在EasyView这个项目中,这......
  • 一个多功能(聚合)查询接口,实现模糊、分页、主键、排序以及多条件查询
    一个多功能(聚合)查询接口,实现模糊、分页、主键、排序以及多条件查询前言写的啰嗦了点,看效果请直接忽略中间,直接看后半部分。引个流,公众号:小简聊开发概念瞎编的名字,哈哈哈,我就勉强称之为聚合查询吧,不知道概念符不符合。大家好,我是小简,很久没写文章了,确实是太忙了,今天我......
  • 等差数列生成器
      1classArithmeticProgression:23def__init__(self,begin,step,end=None):4self.begin=begin5self.end=end6self.step=step789def__iter__(self):10result=typ......
  • LangChain教程 – 如何构建自定义知识聊天机器人
    您可能已经了解到过去几个月发布的大量AI应用程序。您甚至可能已经开始使用其中的一些。ChatPDF和CustomGPTAI等AI工具已经对人们变得非常有用——这是有充分理由的。您需要滚动浏览50页文档才能找到简单答案的日子已经一去不复返了。相反,您可以依靠AI来完成繁重的工作......