hibernate之主键生成策略

本文介绍了Hibernate中的主键类型,包括自然主键和代理主键,并详细解析了各种主键生成策略,如identity、sequence、increment、hilo、native、uuid、guid以及assigned。这些策略分别适用于不同的数据库环境和需求,例如identity适用于某些数据库的自增字段,uuid和guid能确保全局唯一性,而assigned则允许用户手动设置主键值。

一、主键类型
1.自然主键(主键本身就是表中的一个字段,实体中一个具体的属性)
表中已经具有某字段,并且该字段具有业务含义作为主键,称之为自然主键。

例如:在person表中的身份证号,既是唯一的,又可以单独标识一个person

2.代理主键(主键不是实体中某个具体的属性,而是一个不相关的字段)
表中原本不存在的字段,且不具备业务含义的字段作为主键,称之为代理主键。更合理的方式是使用代理主键。

二、主键生成策略
主键生成策略,就是每条记录录入时,主键的生成规则。Hibernate中,提供了几个内置的主键生成策略,其常用主键生成策略的名称和描述如下

1.代理主键
identity(主键自增)
适用于long、short或int类型主键,采用底层数据库本身提供的主键生成标识符。在DB2、MySQL、MS SQL Server、Sybase和HypersonicSQL数据库中可以使用该生成器,该生成器要求在数据库中把主键定义成为自增类型。Oracle没有自动增长

sequence(序列)
适用于long、short或int类型主键,Hibernate根据底层数据库序列生成标识符。条件是数据库支持序列。如oralce、DB、SAP DB、PostgerSQL、McKoi中的sequence,MySQL这种不支持sequence

increment(主键自增,单线程,maxID+1)
适用于long、short或int类型主键,由Hibernate提供自动递增的方式生成唯一标识符,每次增量为1。只有当没有其他进程向同一张表中插入数据时才可以使用,不能再多线程环境下使用

hilo(主键自增,高低位算法)
hilo(高低位方式high low)是hibernate中最常用的一种生成方式,需要一张额外的表保存hi的值。保存hi值的表至少有一条记录(只与第一条记录有关),否则会出现错误。跨数据库,hilo算法生成的标志只能在一个数据库中保证唯一

native(hilo+identity+sequence三选一)
根据底层数据库对自动生成标识符的能力来选择i dentity、sequence、hilo三种生成器中的一种,适合跨数据库平台开发

uuid(随机字符串作主键)
Hibernate采用128位的UUID算法来生成标识符。该算法能够在网络环境中生成唯一的字符串标识符,其UUID被编码为一个长度为32位的十六进制字符串。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字

uuid长度大,占用空间大,跨数据库,不用访问数据库就生成主键值,所以效率高且能保证唯一性,移植非常方便,推荐使用。

guid(全球唯一标识符)
全球唯一标识符,也称作 UUID,是一个128位长的数字,用16进制表示。算法的核心思想是结合机器的网卡、当地时间、一个随即数来生成GUID。

Hibernate在维护主键时,先查询数据库,获得一个uuid字符串,该字符串就是主键值,该值唯一,缺点长度较大,支持数据库有限,优点同uuid,跨数据库,但是仍然需要访问数据库。注意:长度因数据库不同而不同。

需要数据库支持查询uuid,生成时需要查询数据库,效率没有uuid高,推荐使用uuid。

2.自然主键
assigned(用户手动录入)
由Java程序负责生成标识符,Hibernate不管理主键,用户手动设置主键的值。如果不指定id元素的generator属性,则默认使用该主键生成策略。

内容:

1 assigned
数据类型不限、保存前必须赋值

2 identity
数字,无需赋值

3 sequence
数字,无需赋值, 默认使hibernate_sequence这个序列,
也可以通过sequence/sequence_name参数赋值

4 increment
数字,无需赋值

5 uuid/uuid.hex (是由容器自动生成的一个32位的字符串,.hex代表的是十六进制)
32位的字符串,无需赋值,

6 native
等于identity+sequence

导入SessionFactoryUtils类

public class SessionFactoryUtils {
    private static SessionFactory sessionFactory;
//    存放当前会话
    private static ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
    static {
        Configuration cfg = new Configuration();
        Configuration configure = cfg.configure("/hibernate.cfg.xml");
        sessionFactory = configure.buildSessionFactory();
    }
    
    public static Session openSession() {
        Session session = threadLocal.get();
        if (null == session) {
            session = sessionFactory.openSession();
            threadLocal.set(session);
        }
        return session;
    }

    public static void closeSession() {
        Session session = threadLocal.get();
        if (null != session) {
            if (session.isOpen()) {
                session.close();
            }
            threadLocal.set(null);
        }
    }

    public static void main(String[] args) {
        Session session = openSession();
        System.out.println(session.isConnected());
        closeSession();
    }
    
}

这个类在学习hibernate的过程中所用(整合SSH框架之前用)

作用:可以用来检测所写的映射文件是否正确;

然后创建好实体类和实体映射文件

学生类:

public class Student implements Serializable  {
    
      private Integer sid;
      private String sname;
        public Integer getSid() {
            return sid;
        }
        public void setSid(Integer sid) {
            this.sid = sid;
        }
        public String getSname() {
            return sname;
        }
        public void setSname(String sname) {
            this.sname = sname;
        }
        @Override
        public String toString() {
            return "Worker [sid=" + sid + ", sname=" + sname + "]";
        }
}

工人类:

public class Worker implements Serializable{
       private String wid;
       private String wname;
    public String getWid() {
        return wid;
    }
    public void setWid(String wid) {
        this.wid = wid;
    }
    public String getWname() {
        return wname;
    }
    public void setWname(String wname) {
        this.wname = wname;
    }
    @Override
    public String toString() {
        return "Worker [wid=" + wid + ", wname=" + wname + "]";
    }
       
         
    
}

两个实体映射文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="two.entity.Student" table="t_hibernate_student">
        <id name="sid" type="java.lang.Integer" column="sid">
            <!-- <generator class="assigned" />-->
            <!-- <generator class="identity" />  -->
             <generator class="increment" />  
            <!-- <generator class="sequence" /> -->
            <!-- <generator class="sequence" > <param name="sequence_name">aaa</param> 
                </generator> -->
            <!-- <generator class="com.javaxl.two.id.Myts" /> -->
        </id>
        <property name="sname" type="java.lang.String" column="sname">
        </property>
    </class>
</hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="two.entity.Worker" table="t_hibernate_work">
        <id name="wid" type="java.lang.String" column="wid">
            <!-- <generator class="uuid" /> -->
            <!-- <generator class="sequence" /> -->
            <!-- <generator class="sequence" > <param name="sequence_name">aaa</param> 
                </generator> -->
             <generator class="two.id.Myts" /> 
        </id>

        <property name="wname" type="java.lang.String" column="wname">
        </property>
    </class>
</hibernate-mapping>

dao方法

public class DemoDao {
    /**
     * 添加学生
     * @param stu
     * @return
     */
       public Serializable addStudent(Student stu) {
           Session session=SessionFactoryUtils.openSession();
           Transaction transaction=session.beginTransaction();
           Serializable saveId=session.save(stu);
           transaction.commit();
           session.close();
           return saveId;
       }
       /**
        * 添加工人
        * @param worker
        * @return
        */
       public Serializable addWork(Worker worker) {
           Session session=SessionFactoryUtils.openSession();
           Transaction transaction=session.beginTransaction();
           Serializable saveId=session.save(worker);
           transaction.commit();
           session.close();
           return saveId;
       }
     
       
       
//       public static void teststudent(String[] args) {
//           
//           DemoDao dao=new DemoDao();
//           Student stu=new Student();
////           stu.setSid(4);
//           stu.setSname("张三");
//           dao.addStudent(stu);
//           System.out.println(dao.addStudent(stu));
//    }
       public static void main(String[] args) {
           DemoDao dao=new DemoDao();
           Worker worker=new Worker();
           worker.setWname("啊哈哈哈");
           System.out.println(dao.addWork(worker));
    }
       
      
}

各位大佬们可以一一去试

最后一个自定义主键生成器

需要创建一个类来设置你需要变成的id格式

如下:

public class Myts implements IdentifierGenerator {

    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
        // TODO Auto-generated method stub
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return "shop_book_"+sdf.format(new Date());
    }

}

在dao方法类运行:

显示如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值