Hibernate主键生成策略比较多,需要对这几种策略有一定的了解才能更好的服务于你的项目,下面对几种常见的Hibernate的主键生成策略进行解读,一方面可以当做读者的学习资料,另一方面可以为自己起到备忘录的作用。
大概有几种常见的主键生成策略:
1. increment:由Hibernate代理自增生成主键,跟数据库没有关系(注:只是生成的时候没关系,并不是插入的时候不往数据库里面插),这种方式是跨数据库的,但是有一点需要注意的是:不适用于两个以及两个以上的Hibernate进程的情况。Hibernate调用org.hibernate.id.incrementGenerator类里面的generate方法时,会执行查询语句select max(主键所在的列名) from table;该方法上面有synchronized,在一个独立的java虚拟机里面运行时没有问题的,如果多个java虚拟机同时去查询最大的主键的时候,最后生成的主键是一样的主键值,那么在插入数据的时候就会发生冲突,从而抛出异常信息。不适合多进程并发的访问数据库,适合单一的进程来访问数据库,但是不适用于集群环境。
<id name="id" column="id"> <generator class="increment" /> </id>
<id name="id" column="id"> <generator class="identity" /> </id>
3. sequence:由数据库负责生成主键,Hibernate不用负责,但是这种方式适用于oracle这种支持序列的数据库。
生成主键的时候,查询sequence然后赋值给主键值,使用的时候必须先创建一个sequence才行,如果不指定sequence名称那么会默认使用hibernate_sequence,要在数据库中创建这个sequence才行。
<generator class="sequence"> <param name="sequence">hibernate_id</param> </generator> <param name="sequence">hibernate_id</param> 指定sequence的名称
4. native:根据数据库的特性选择使用哪种合适的主键生成策略,会被转为其他的主键生成策略,比如说Mysql数据库会使用前面提到的identity主键生成策略,而如果是oracle数据库的时候,就会使用另一种主键生成策略:sequence主键生成策略。
<id name="id" column="id"> <generator class="native" /> </id>
5. hilo:使用高低位算法生成主键,由Hibernate负责生成主键,该算法生成的标志只能保证在一个数据库中唯一。
需要一张额外的表来存储high的值,只和第一条数据有关系,至少要有一条数据。
hilo方式生成主键的过程:
1). 读取high值,表已经指定的话就读取指定的表中的数据,然后读取完成值+1,如果没有进行指定的话,默认读取hibernate_unique_key表中的next_hi字段的值,读完同样的+1。
2). 获取low值,从0到最大的那个low值,循环的取值,如果获取的是最大的low值的时候就重新获取high值,然后low继续从0-最大low循环。
3). 由公式:high*(maxLow + 1) + low
如果需要建立大量的主键并且不需要经常重启的话,就将high设置的大一些,否则设置稍微小一些比较好,如果设置为0的时候就是自然数序列了1,2,3,4,5.....
<id name="id" column="id"> <generator class="hilo"> <param name="table">hibernate_hilo</param> <param name="column">next_hi</param> <param name="max_lo">100</param> </generator> </id> <param name="table">hibernate_hilo</param> 指定保存hi值的表名 <param name="column">next_hi</param> 指定保存hi值的列名 <param name="max_lo">100</param> 指定低位的最大值
6. uuid:Hibernate计算出一个128位的唯一的标识,作为主键.用到了以太网卡、纳秒级时间、芯片Id码等等来保证唯一性。该方式可以跨数据库,推荐使用。
<id name="id" column="id"> <generator class="uuid" /> </id>
7. assigned:默认的主键生成策略,但是这种方式是用户自己去指定。它和Hibernate、数据都没有必然的联系,纯粹需要你去指定,灵活可跨数据库使用但是危险性比较大,储存对象的时候需要为对象设置好主键值。不是很建议使用。使用时不能将属性设置为private,否则无法为主键赋值。