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 工具类
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
断点不继续的前提下运行项目
运行结果
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:手动添加主键(不推荐) |