在往数据库中插入数据的时候,我们一般都要为数据指定一个主键,不管这个主键是物理主键,还是设置的仅仅起到标示作用的逻辑主键,从工程实践中来看,一般都是设置一个逻辑主键,尽量避免使用full -primary key。
在用hibernate操作数据库的时候,主键可以自己指定,也可以自己实现自己的主键生成策略类,只需要实现org.hibernate.id.IdentifierGenerator这个接口即可。但是我们一般都是使用hibernate已经为我们内建好的主键生成策略类。在hibernate中,使用hibernate内建主键生成器有两种方式,一种方式是使用XML方式,一种是使用Annotation。当使用了JPA的时候,一般建议直接使用Annotation。这样简洁直观,现在讲两种常用的主键生成策略配置方式详细讲解如下。
1:XML方式
1.1:increament策略
<class name="Student" table="student">
<id name="id" column="id">
<generator class="increament"></generator>
</id>
<property name="..." column="...."/>
</class>
这种方式,也就是自增,此种方式一般不适用,尤其是在有并发访问涉及到同步的时候,一定不能使用。设想一下,假设A,B两个服务器在TimeA这个时刻,各自保存的数据库主键值为X,这个时候,A往数据库中插入一个值,此时A保存下一个数据库记录主键值X+1,但是B服务器对这些并不知情,当B 用主键A往数据库中插入一条数据的时候,发生主键冲突。插入失败!!!
1.2:identity
策略
<class name="Student" table="student">
<id name="id" column="id">
<generator class="identity"></generator>
</id>
<property name="..." column="...."/>
</class>
此种方式使用广泛,对DB2,MySQL,SQL Server等提供支持,通过在hiberante.cfg.xml中配置show_sql=“true”,查看打印的建表语句,我们发现,其对应到数据库中时,对应的主键字段是auto_increament类型的。这种方式,不必多说。
1.3:sequence策略
<class name="Student" table="student">
<id name="id" column="id">
<generator class="sequence"></generator>
</id>
<property name="..." column="...."/>
</class>
此种方式使用广泛,对DB2,Oracle ,DB等提供支持,使用序列。默认在数据库中会生成一张Hibernate_Sequence的序列表,这个时候,所有的主键生成的时候都会去参考这张表。在Annotation中可以方便的配置使得每个数据表对应一个自定义序列表。这样就可以避免所有数据表参考同一个序列表导致的主键不连续的情况。不过这样做意义并不大,因为前面说过,我们一般会为数据库中的每条数据制定一个逻辑主键,而逻辑主键是没有实际意义的,所以,其连续与否对程序关系并不大。
1.4:uuid策略
<class name="Student" table="student">
<id name="id" column="id">
<generator class="uuid"></generator>
</id>
<property name="..." column="...."/>
</class>
首先,当使用这种主键生成主键时,一定保证你的实体类主键时String类型,否则报错,这种策略是通过自己本机IP,MAC地址来计算的128bit长的字符串,使用这种策略保证所生成的主键值在全网内是唯一的。这个,看名字就知道,uuid = universal unique identifier。
guid主键生成策略和uuid,可以认为其没有区别,guid :即全球唯一标示符的缩写。
1.5:native策略
<class name="Student" table="student">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="..." column="...."/>
</class>
此种方式使用广泛,hibernate会根据底层的数据库的特性来自动选择
identity
, sequence或者hilo
这三中主键生成策略中的一种,注意常用两种常用的数据库。MySQL:此时选择的是identity,也就是主键自增。Oracle:此时选择的是sequence,通过序列表来生成主键。
1.6:assigned策略
<class name="Student" table="student">
<id name="id" column="id">
<generator class="assigned"></generator>
</id>
<property name="..." column="...."/>
</class>
无需多说,此种方式是Hibernate的模式实现,也就是hibernate不帮我们添加主键值,我们必须为每个我们插入到数据库中值手动设定主键值。
1.7:foreign策略
<class name="Student" table="student">
<id name="id" column="id">
<generator class="foreign"></generator>
</id>
<property name="..." column="...."/>
</class>
这种方式一般在有一对一关联映射中常用,比如A,B关联(一对一),此时A,B中有一个的主键值是参考的另外的一个的,当其中被参照对象的主键值被指定后,其参照对象的主键值就定了。
1.8:其他的hilo,sequencehilo等并不常用,错了。是十分的不常用。所以,此处不详细讲解,具体可参考doc文档。
1.9:联合主键生成策略。
“联合主键”,顾名思义,就是多个属性作为一个持久化对象的标识属性,现在就有一种情况,假如学生如果用id,name作为联合主键,现在我们就让Student类中存放id,name主键属性,这种方式实际上是用持久化对象本身作为自己的标识符,这样是一种什么样的结果?这样做的结果就是当你要加载一个与组合主键关联的处于持久化状态的对象之前我们必须实例化一个持久化类的实例并且为其赋予标志属性,这在实际开发时,是不鼓励这么做的。现在我们从更加“面向对象”开发的角度来思考,我们发现可以将逐渐属性单独的拿出来形成一个“主键类”,用这个主键类来标识我们的持久化对象。这样不仅仅易于理解,也降低了代码耦合度。
示例:(假设我们代码有一个Student类,由id,name两个标志属性来唯一标志持久化对象,现在我么将建立一个主键类,在Person中来引用这个主键类)
主键类:StudentPK
几点说明:
1:逐渐类必须要实现Seralizable接口,因为实现了这个接口,我们才可以将逐渐类序列化到磁盘,后者通过网络来传输。
2:必须重写hashCode和equals方法,重写hashCode方法,是为了在Session这个一级缓存中保存的hash表中快速找到对象所属的列表,重写equals方法是为了和查找到得到列表中的元素对比,看是否有相等的元素存在。
public class StudentPK implements java.io.Serializable{
private int id;
private String name;
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;
}
@Override
public boolean equals(Object obj){
if (obj instanceof StudentPK) {
StudentPK stu_PK = (StudentPK) obj;
if(this.id == stu_PK.getId() && this.name == stu_PK.getName()){
return true;
}
}
return false;
}
@Override
public int hashCode(){
return this.name.hashCode();
}
}
持久化类:Student
public class Student {
private int age;
private StudentPK pk;
public StudentPK getPk() {
return pk;
}
public void setPk(StudentPK pk) {
this.pk = pk;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
联合主键配置文件XML
<composite-id name="pk" class="com.zxb.model.StudentPK">
<key-property name="id"></key-property>
<key-property name="name"></key-property>
</composite-id>