Web开发 | Hibernate - 05.主键的生成策略

1.主键类型之自然主键和代理主键

1、创建表的时候

  1)、自然主键:对象本身的一个属性.创建一个人员表,每个人都有一个身份证号.(唯一的)使用身份证号作为表的主键.自然主键.(开发中不会使用这种方式)

  2)、代理主键:不是对象本身的一个属性.创建一个人员表,为每个人员单独创建一个字段.用这个字段作为主键.代理主键.(开发中推荐使用这种方式)

2、创建表的时候尽量使用代理主键创建表


2.主键的生成策略

1、increment:适用于 short,int,long 作为主键.
不是使用数据库自动增长机制
Hibernate 中提供的一种增长机制
先进行查询:select max(id) from person;
再进行插入:获得最大值+1 作为新的记录的主键
问题:不能在集群环境下或者有并发访问的情况下使用
2、identity:适用于 short,int,long 作为主键。
但是这个必须使用在有自动增长数据库中.采用的是数据库底层的自动增长机制
底层使用的是数据库的自动增长(auto_increment).像 Oracle 数据库没有自动增长
3、sequence:适用于 short,int,long 作为主键.
底层使用的是序列的增长方式
Oracle 数据库底层没有自动增长,想自动增长需要使用序列
4、uuid:适用于 char,varchar 类型的作为主键 使用随机的字符串作为主键
5、native:本地策略.根据底层的数据库不同,
自动选择适用于该种数据库的生成策略.(short,int,long)
如果底层使用的 MySQL 数据库:相当于 identity
如果底层使用 Oracle 数据库:相当于 sequence
6、assigned:主键的生成不用 Hibernate 管理了. 必须手动设置主键

3.increment主键策略

  由 hibernate 来生成 OID 和维护的,原理是 select max(id) + 1
  如果数据表中没有数据,则初始的时候,hibernate 给值是 1,再次给值 2

适用场景:适用于只有单个Hibernate应用进程访问同一个数据库的场合

问题:可能出现多线程冲突问题,两个线程同时查询 max(id),同时+1 ,insert


1、新建 web 项目,添加 hibernate、mysql 驱动以及日志架包


2、新建 hibernate_day02 数据库,并新建 t_person 表

注意:主键自增选项打钩
数据表
数据表


3、新建 Person 类
  /Hibernate5_d02_c01/src/hibernate/domain/Person.java
程序代码如下:

package hibernate.domain;

public class Person {
    private int id;
    private String name;
    private int age;

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

}

4、编写配置文件 Person.hbm.xml
  /Hibernate5_d02_c01/src/hibernate/domain/Person.hbm.xml
程序代码如下:

<?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>
    <!-- javabean与表之间的对应关系 -->
    <class name="hibernate.domain.Person" table="t_person">
        <!-- 主键对应 -->
        <id name="id" column="id">
            <!-- 主键生成策略 -->
            <!-- hibernate框架来产生主键 整型 -->
            <!-- 在多线程情况下不能用这种方式 -->
            <generator class="increment"></generator>
        </id>
        <!-- 其他字段 -->
        <property name="name" column="name"></property>
        <property name="age" column="age"></property>
    </class>
</hibernate-mapping>

5、编写配置文件 hibernate.cfg.xml
  /Hibernate5_d02_c01/src/hibernate.cfg.xml
程序代码如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
    <session-factory>
        <!-- 必选配置 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
                <!-- jdbc:mysql:///hibernate_day01 -->
        <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/hibernate_day02</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">root</property>
                <!--数据库方言 使用的数据库类型  -->
        <property name="hibernate.dialect org.hibernate.dialect.MySQLDialect"></property>

        <!-- 可选配置 -->
                <!-- 在控制台输出sql语句 -->
        <property name="show_sql">true</property>
                <!-- 在控制台输出的sql语句格式化 -->
        <property name="hibernate.format_sql">true</property>
                <!-- 配置c3p0连接池 -->
                    <!-- C3P0 的供应商 -->
        <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
                    <!-- 最小连接 -->
        <property name="hibernate.c3p0.min_size">5</property>
                    <!-- 最大连接数 -->
        <property name="hibernate.c3p0.max_size">10</property>
                    <!-- 每 120 秒检查空闲连接 -->
        <property name="hibernate.c3p0.timeout">120</property>
                <!-- 自动建表 -->
        <property name="hibernate.hbm2ddl.auto">update</property>

        <!-- 映射文件 -->
        <mapping resource="/hibernate/domain/Person.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

6、拷贝第一天编写的 hibernate 工具类

hibernate 工具类
hibernate 工具类


7、编写测试类TestPerson.java
  /Hibernate5_d02_c01/src/hibernate/test/TestPerson.java
程序代码如下:

package hibernate.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import hibernate.domain.Person;
import hibernate.util.HibernateUtils;

public class TestPerson {
    Session session = null;
    Transaction tr = null;
    @Before
    public void init(){
        //获取 session
        session = HibernateUtils.openSession();
        //开启事务
        tr = session.beginTransaction();
    }
    @Test
    public void save(){
        //创建 Person 对象
        Person c = new Person();
        c.setName("小红");
        c.setAge(18);
        session.save(c);
    }
    @After
    public void destory(){
        //提交事务
        tr.commit();
        //释放资源
        session.close();
    }
}

8、运行项目

运行效果
运行效果


9、验证多线程冲突

打断点
打断点
debug产生第一个id
debug产生第一个id
断点不继续的前提下运行项目
断点不继续的前提下运行项目
运行结果
运行结果

然后返回到debug运行项目
F8
F8
线程冲突
线程冲突


4.identity主键策略

1、删除 hibernate_day02 数据库中的 t_person 表

2、修改 Person.hbm.xml
/Hibernate5_d02_c01/src/hibernate/domain/Person.hbm.xml
程序代码如下:

<?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>
    <!-- javabean与表之间的对应关系 -->
    <class name="hibernate.domain.Person" table="t_person">
        <!-- 主键对应 -->
        <id name="id" column="id">
            <!-- 主键生成策略 -->
            <!-- identity主键由数据库产生,适用于MySQL -->
            <generator class="identity"></generator>
        </id>
        <!-- 其他字段 -->
        <property name="name" column="name"></property>
        <property name="age" column="age"></property>
    </class>
</hibernate-mapping>

3、运行项目

运行结果
运行结果

4、验证支持多线程

方法同上


5.uuid主键策略

  用于 String 类型,生成代理主键,采用 uuid (32 位)作为主键值
  Hibernate 会产生不重复的 32 位字符串作为主键

1、修改 Person 类,添加 uuid 属性
  /Hibernate5_d02_c01/src/hibernate/domain/Person.java
程序代码如下:

package hibernate.domain;

public class Person {
    ...
    private String uuid;
    public String getUuid() {
        return uuid;
    }
    public void setUuid(String uuid) {
        this.uuid = uuid;
    }
    ...
}

2、修改 Person.hbm.xml 的 id 节点
  /Hibernate5_d02_c01/src/hibernate/domain/Person.hbm.xml
程序代码如下:

<?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>
    <!-- javabean与表之间的对应关系 -->
    <class name="hibernate.domain.Person" table="t_person">
        <!-- 主键对应 -->
        <id name="uuid" column="uuid">
            <!-- 主键生成策略 -->
            <!-- uuid产生32位随机数,String类型,可以在多线程情况下使用 -->
            <generator class="uuid"></generator>
        </id>
        <!-- 其他字段 -->
        <property name="name" column="name"></property>
        <property name="age" column="age"></property>
    </class>
</hibernate-mapping>

3、运行项目

运行效果
运行效果
运行效果

4、验证多线程

方法同上


6.assigned主键策略

  唯一的一个自然主键设置方式,手动设置主键的值。

1、修改 Person.hbm.xml 的 id 生成策略
/Hibernate5_d02_c01/src/hibernate/domain/Person.hbm.xml
程序代码如下:

<?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>
    <!-- javabean与表之间的对应关系 -->
    <class name="hibernate.domain.Person" table="t_person">
        <!-- 主键对应 -->
        <id name="uuid" column="uuid">
            <!-- 主键生成策略 -->
            <!-- 唯一的一个自然主键设置方式,手动设置主键的值。 -->
            <generator class="assigned"></generator>
        </id>
        <!-- 其他字段 -->
        <property name="name" column="name"></property>
        <property name="age" column="age"></property>
    </class>
</hibernate-mapping>

2、修改测试代码
  /Hibernate5_d02_c01/src/hibernate/test/TestPerson.java
程序代码如下:

package hibernate.test;

import java.util.UUID;

...

public class TestPerson {
    ...
    @Test
    public void save1(){
        //创建 Person 对象
        Person c = new Person();
        c.setName("小红");
        c.setAge(18);
        //手动设置主键
        c.setUuid(UUID.randomUUID().toString());
        session.save(c);
    }
    ...
}

3、运行项目

运行结果
运行结果


7.主键生成策略小结

代理主键
increment:由框架产生,整型,适合单线程
identity:由数据库产生(MySQL) 整型
sequence:由数据库产生(Oracle) 整型
uuid:由框架产生,字符串类型,适合多线程
native:identity + sequence ,根据不同的数据库产生不同主键
自然主键 assigned:手动添加主键(不推荐)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值