原创

JPA使用雪花算法自动生成唯一主键ID

温馨提示:
本文最后更新于 2020年11月17日,已超过 1,479 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

平常使用

UUID自动生成主键,但是尽量还是不要使用UUID作为主键,在数据量大的时候,UUID做主键稍显慢一点。

好处就是本地生成,不要基于数据库来了;不好之处就是,UUID 太长了、占用空间大,作为主键性能太差了;更重要的是,UUID 不具有有序性,会导致 B+ 树索引在写的时候有过多的随机写操作(连续的 ID 可以产生部分顺序写),还有,由于在写的时候不能产生有顺序的 append 操作,而需要进行 insert 操作,将会读取整个 B+ 树节点到内存,在插入这条记录后会将整个节点写回磁盘,这种操作在记录占用空间比较大的情况下,性能下降明显。

总而言之,就是:

  1. innodb中的主键索引也是聚集索引,如果插入的数据是顺序的,那么b+树的叶子基本都是满的,缓存也可以很好的发挥作用。如果插入的数据是完全无序的,那么叶子节点会频繁分裂,缓存也基本无效了。这会减少tps。
  2. uuid占用的空间较大。
@Id
@GeneratedValue(generator = "uuidGenerator")
@GenericGenerator(name = "uuidGenerator", strategy = "uuid")
@Column(nullable = false, length = 32)
private String id;

如何改进?

其实MySQL官方是推荐使用自增主键作为ID性能是最好的,但是在对于分布式环境中、数据量大的情况下、分库分表的时候,使用自增主键就不太好了。推荐还是使用雪花算法。那么JPA中我们知道有直接使用注解UUID的,我们可以写一个使用雪花算法的。

配置类SnowflakeProperties

雪花算法配置:

@Data
@Configuration
@ConfigurationProperties(prefix = "snowflake")
public class SnowflakeProperties {

    /**
     * 工作节点ID
     */
    private Long workerId;

    /**
     * 数据中心ID
     */
    private Long datacenterId;
}

初始化SnowFlake配置/Bean

初始化Bean:

@Configuration
@RequiredArgsConstructor
public class SnowFlake {

    private final SnowflakeProperties snowflakeProperties;

    /**
     * 初始化SnowflakeIdWorker Bean
     *
     * @return SnowflakeIdWorker
     */
    @Bean
    public Snowflake snowflake() {
        return new Snowflake(snowflakeProperties.getWorkerId(), snowflakeProperties.getDatacenterId());
    }
}

集成JPA配置GenerateSnowflakeId

实现接口IdentifierGenerator,类路径com.lzhpo.snowflake.GenerateSnowflakeId

public class GenerateSnowflakeId implements IdentifierGenerator, Configurable {

    @Override
    public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
    }

    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
        return SpringUtil.getBean(Snowflake.class).nextId();
    }
}

使用

使用:

com.lzhpo.snowflake.GenerateSnowflakeId就是GenerateSnowflakeId

@Id
@GenericGenerator(name = "snowflakeId", strategy = "com.lzhpo.snowflake.GenerateSnowflakeId" )
@GeneratedValue(generator = "snowflakeId")
@Column(name = "id")
private Long id;
本文目录