Spring Boot之Spring Data JPA自定义ID策略

如何指定id策略

在JPA中,我们是通过@id@GeneratedValue来指定id主键和id策略的,比如:

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private String id;
  
  
  • 1
  • 2
  • 3
  • 4

这样也就指定了id和生成id所使用的策略,下面我们来看一下都有哪些策略呢

4种JPA策略用法

我们点进@GeneratedValue源码里可以看到,strategy属性是由GenerationType指定的,我们点进GenerationType里面可以看到这里定义了四种策略:
- TABLE:使用一个特定的数据库表格来保存主键。
- SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。
- IDENTITY:主键由数据库自动生成(主要是自动增长型)
- AUTO:主键由程序控制(也是默认的,在指定主键时,如果不指定主键生成策略,默认为AUTO)
这些策略也不是所有数据库都支持的,支持情况如下表:

策略\数据库mysqloraclepostgreSQLkingbase
TABLE支持支持支持支持
SEQUENCE不支持支持支持支持
IDENTITY支持不支持支持支持
AUTO支持支持支持支持

Hibernate拓展id策略

当然,很多时候,这么几种策略并不够用,这里hibernate也拓展了JPA的id策略,我们可以在org.hibernate.id.IdentifierGeneratorFactory中看到,主要提供了这么些策略:
1. native: 对于oracle采用Sequence方式,对于MySQL和SQL Server采用identity(自增主键生成机制),native就是将主键的生成工作交由数据库完成,hibernate不管(很常用)。
2. uuid: 采用128位的uuid算法生成主键,uuid被编码为一个32位16进制数字的字符串。占用空间大(字符串类型)。
3. hilo: 使用hilo生成策略,要在数据库中建立一张额外的表,默认表名为hibernate_unique_key,默认字段为Integer类型,名称是next_hi(比较少用)。
4. assigned: 在插入数据的时候主键由程序处理(很常用),这是generator元素没有指定时的默认生成策略。等同于JPA中的AUTO。
5. identity: 使用SQL Server和MySQL的自增字段,这个方法不能放到Oracle中,Oracle不支持自增字段,要设定sequence(MySQL和SQL Server中很常用)。等同于JPA中的IDENTITY。
6. select: 使用触发器生成主键(主要用于早期的数据库主键生成机制,少用)。
7. sequence: 调用底层数据库的序列来生成主键,要设定序列名,不然hibernate无法找到。
8. seqhilo: 通过hilo算法实现,但是主键历史保存在Sequence中,适用于支持Sequence的数据库,如Oracle(比较少用)。
9. increment: 插入数据的时候hibernate会给主键添加一个自增的主键,但是一个hibernate实例就维护一个计数器,所以在多个实例运行的时候不能使用这个方法。
10. foreign: 使用另外一个相关联的对象的主键。通常和联合起来使用。
11. guid: 采用数据库底层的guid算法机制,对应MYSQL的uuid()函数,SQL Server的newid()函数,ORACLE的rawtohex(sys_guid())函数等。
12. uuid.hex: 看uuid,建议用uuid替换。
13. sequence-identity: sequence策略的扩展,采用立即检索策略来获取sequence值,需要JDBC3.0和JDK4以上(含1.4)版本 。
具体使用就是多了一个@GenericGenerator注解,指定策略,指定自定义名称,然后在@GeneratedValue中使用该策略,比如:

@Id
@GeneratedValue(generator  = "myIdStrategy")
@GenericGenerator(name = "myIdStrategy", strategy = "uuid")
@Column(name = "id")
private String id;
  
  
  • 1
  • 2
  • 3
  • 4
  • 5

其他的类似,就不再多举例了

到这里已经有很多策略供我们使用了,但是呢,有时候比如分布式系统中要求全局id唯一,或者其他一些场景,要求我们有自己的策略,那么该怎么做呢?

使用的id策略(以snowflake为例)

在看其他策略源码的时候,我们发现他们实现了这样一个接口IdentifierGenerator,他位于org.hibernate.id包下,我们进入该类,就可以看到源码注释上写着用户实现此接口可以实现自定义id策略
那么就很简单了,我们实现一下这个接口:

public class SnowflakeId implements IdentifierGenerator{
    .
    .
    .
    @Override
    public Serializable generate(SessionImplementor s, Object obj) {
        return getId() + "";
    }
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

实现generate方法,方法体调用我们生成id的方法就好了,这里省略了生成过程,有需要可以去我代码里找一下。

注意IdentifierGenerator接口里面还写了一句注释,必须要实现一个默认的无参构造。当时实现的就少看了这一句,折腾了好久(手动捂脸)。所以大致是这样的:

public class SnowflakeId implements IdentifierGenerator{

    public SnowflakeId() {
    }
    .
    .
    .

    @Override
    public Serializable generate(SessionImplementor s, Object obj) {
        return getId() + "";
    }
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

自定义完了之后,我们只需要在指定策略的时候使用我们自定义的就好了,@GenericGenerator注解的strategy属性上说了,使用非默认策略的时候,需要使用全类名,即:

@Id
@GeneratedValue(generator = "snowFlakeId")
@GenericGenerator(name = "snowFlakeId", strategy = "top.felixu.idworker.SnowflakeId")
@Column(name = "id")
private String id;
  
  
  • 1
  • 2
  • 3
  • 4
  • 5

这样我们就实现了自己的id策略了

示例代码

破代码

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值