`

hibernate主键生成策略

 
阅读更多
看尚学堂Hibernate视频做的一些笔记,仅供参考。。。

Mysql的自增字段用auto_increment,Oracle的自增字段用sequence。

<generator class=”increment”></generator>在集群环境下不要使用,因为ID容易重复。Increment用的很少。

当generator是native时,表示根据数据库选择用identity(mysql下就是auto_increment),sequence(Oracle下)或者hilo。用的最多。此时Id要是int类型,Identity,sequence和uuid(要求id是String类型)用的也挺多。要想使数据库跨平台,应该用native或者uuid。

Oracle中表名不允许用_开头。

在Annotation中加ID生成器就是在@Id注解下加@GeneratedValue,默认是AUTO,相当于xml的native,对MySQL使用auto_increment,对Oracle使用HIBERNATE_SEQUENCE(名称固定,先用select hibernate_sequence.nextval from dual取出最大值),对SqlServer用identity。

@GeneratedValue还可以是INDENTITY,SEQUENCE,TABLE,如@GeneratedValue(strategy=GenerationType.IDENTITY)

要想Oracle中产生的sequence的 名字是自己定义的,可以如下:

在@Entity下加@SequenceGenerator(name=”teacherSequence”, sequenceName=”teacherSequence_DB”),name指的是这个sequence生成器的名字,sequenceName指的是在数据库中生成的sequence的名字。

然后@GeneratedValue(strategy=GenerationType.SEQUENCE, generator=” teacherSequence”)

这样该实体类所用的sequence就是teacherSequence_DB这个sequence了。

也可以定义TableGenerator,用生成的表中的数值来生成主键,做法如下:

在@Entity下加@TableGenerator(

                name=”Teacher_GEN”,

                table=”GENERATOR_TABLE”,

                pkColumnName=”pk_key”,不能用key,因为是关键词

                valueColumnName=”pk_value”,

                pkColumnValue=”Teacher”,

                allocationSize=1

)

生成的表名为GENERATOR_TABLE,总共有两个字段,主键的字段名为key,另一个字段名为value。pkColumnValue=”Teacher”,指的是有一条记录,这条记录的key是Teacher,默认的value字段的值是1,value字段的值就是要拿到的id值。取完一个值后,这条记录的value字段的值就加上allocationSize的值,变成了2. 拿id值的sql语句相当于select value from GENERATOR_TABLE where key = ‘Teacher’;     如果这个TableGenerator为n张表提供id值,那么相应的就有n条记录,只是每条记录的key值不一样而已。

然后使用的话在@Id注解下加上@GeneratedValue(strategy=GenerationType.TABLE, generator=” Teacher_GEN”)

这种TableGenerator可以跨数据库平台,里面的数据也可以跨平台。不过实际上跨数据库平台这种需求比较少。

@Entity下可以定义多个Generator,下面要用哪个就写哪个的name值。

基于xml的联合主键:

先写一个主键类,如StudentPK,里面只有id,name两个字段。再加上get,set方法。然后再Student类中声明private StudentPK pk;                    Student和StudentPK是组合关系。

然后在Student.hbm.xml映射文件中加入:

<composite-id name=”pk” class=”com.hibernate.StudentPK”>

                <key-property name=”id” ></key-property>

                <key-property name=”name” ></key-property>

</composite-id>

StudentPK还要重写equals,hashCode方法(保证StudentPK对象都是唯一的),实现Serializable接口(因为要把StudentPK对象进行序列化(写到硬盘上,或者进行网络传输),即固化到数据库中。或者当某台服务器死机的时候可以把内存中的Student对象传输到另一台服务器中。或者当内存满了的时候,使用虚拟内存(把硬盘上的一部分空间作为内存),这样就可以把一部分Student对象序列化到硬盘上)。

重写equals方法:

@Override

public Boolean equals(Object o) {

                if (o instanceof StudentPK) {

                                StudentPK pk = (StudentPK) o;

                                If (this.id == pk.getId() &&  this.name.equals(pk.getName())) {

                                                Return true;

                                }

                }

                Return false;

}

重写hashCode方法

@Override

public int hashCode() {

                return this.name.hashCode();

}

hashTable的结构:实际上hashTable很多时候就是一个数组,数组里面有很多位置,hashCode相同的对象是放在同一个位置中的,所以同一个位置中的对象往往是以链表的形式存放的。链表里所有的对象都是hashCode相同的。当我们从hashTable中查找一个对象时,先根据该对象的hashCode找到相应的位置,再遍历这个位置中的链表中的对象,根据equals方法进行匹配。

要将一系列的Student对象装到HashTable中,需要先计算每个Student对象的hashCode,然后根据hashCode将Student对象装到HashTable中。但不会直接计算Student对象的hashCode,因为数据库的逻辑,区分不同的Student对象是根据StudentPK来决定的,所以应该计算StudentPK对象的hashCode。

基于Annotation的联合主键:

一共有三种做法:

将组件类注解为@Embeddable,并将组件的属性注解为@Id
即将TeacherPK注解为@Embedddable(可以被嵌入的),将Teacher类中的public TeacherPK getPk(){}注解为@Id,而不是将TeacherPK中的属性注解为@Id。

将组件的属性注解为@EmbeddedId
不要将TeacherPK注解为@Embedddable,直接将Teacher类中的public TeacherPK getPk(){}注解为@EmbeddedId,这种比较常用。

将类注解为@IdClass,并将该实体中所有属于主键的属性都注解为@Id
Teacher类中不需要TeacherPK属性,还是以前的id和name,在Teacher类前加上@IdClass(TeacherPK.class),然后在id和name的get方法前都加@Id就可以了。但是这时从数据库中读取记录的时候或者把Teacher对象存放在Map中时还是需要TeacherPK主键对象的。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics