springBoot中雪花算术法

在 Spring Boot 中,雪花算法(Snowflake Algorithm)通常指的是 Twitter 开发的一种分布式唯一 ID 生成算法。它被广泛用于分布式系统中生成全局唯一的 ID,尤其是在高并发场景下。雪花算法生成的 ID 是一个 64 位的长整型数字,具有时间有序性和唯一性。

虽然 Spring Boot 本身没有直接内置雪花算法的实现,但你可以通过自定义代码或引入第三方库来实现它。下面我将解释雪花算法的原理,并提供一个在 Spring Boot 中实现的示例。


雪花算法原理

雪花算法生成的 64 位 ID 由以下部分组成:

  1. **1 位符号位**:通常为 0,表示正数。

  2. **41 位时间戳**:表示毫秒级时间戳,通常是当前时间与某个起始时间(epoch)的差值,可支持约 69 年的时间范围。

  3. **10 位机器 ID**:表示机器或进程的标识,支持 1024 个节点。

  4. **12 位序列号**:每毫秒内的自增序列号,支持每毫秒生成 4096 个 ID。

生成的 ID 结构如下:

```

0 | 41-bit timestamp | 10-bit worker ID | 12-bit sequence

```

优点:

  • 高性能、高并发下仍能保证唯一性。

  • ID 是时间有序的,便于排序和存储。

  • 不依赖数据库等外部系统。


在 Spring Boot 中实现雪花算法

以下是一个简单的雪花算法实现示例,你可以将其集成到 Spring Boot 项目中。

1. 创建雪花算法工具类

```java

public class SnowflakeIdGenerator {

// 起始时间戳 (例如 2023-01-01 00:00:00)

private static final long START_TIMESTAMP = 1672531200000L;

// 各部分位数

private static final long WORKER_ID_BITS = 10L; // 机器 ID 占 10 位

private static final long SEQUENCE_BITS = 12L; // 序列号占 12 位

// 最大值

private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS); // 1023

private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS); // 4095

// 位移量

private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;

private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;

private long workerId; // 机器 ID

private long sequence = 0L; // 序列号

private long lastTimestamp = -1L; // 上次生成 ID 的时间戳

public SnowflakeIdGenerator(long workerId) {

if (workerId > MAX_WORKER_ID || workerId < 0) {

throw new IllegalArgumentException("Worker ID must be between 0 and " + MAX_WORKER_ID);

}

this.workerId = workerId;

}

// 生成下一个 ID

public synchronized long nextId() {

long currentTimestamp = System.currentTimeMillis();

// 时钟回拨检查

if (currentTimestamp < lastTimestamp) {

throw new RuntimeException("Clock moved backwards. Refusing to generate ID.");

}

// 如果是同一毫秒内,序列号自增

if (currentTimestamp == lastTimestamp) {

sequence = (sequence + 1) & MAX_SEQUENCE;

// 序列号溢出,等待下一毫秒

if (sequence == 0) {

currentTimestamp = waitNextMillis(currentTimestamp);

}

} else {

sequence = 0L; // 新毫秒,序列号重置

}

lastTimestamp = currentTimestamp;

// 组合 ID

return ((currentTimestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT) |

(workerId << WORKER_ID_SHIFT) |

sequence;

}

// 等待下一毫秒

private long waitNextMillis(long currentTimestamp) {

long timestamp = System.currentTimeMillis();

while (timestamp <= currentTimestamp) {

timestamp = System.currentTimeMillis();

}

return timestamp;

}

}

```

2. 在 Spring Boot 中使用

将上述工具类注入到 Spring Boot 的服务中,例如:

```java

import org.springframework.stereotype.Service;

@Service

public class IdGeneratorService {

private final SnowflakeIdGenerator idGenerator;

public IdGeneratorService() {

// 假设 workerId 为 1,可以通过配置动态设置

this.idGenerator = new SnowflakeIdGenerator(1L);

}

public long generateId() {

return idGenerator.nextId();

}

}

```

3. 调用示例

在 Controller 中调用服务生成 ID:

```java

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;

@RestController

public class IdController {

@Autowired

private IdGeneratorService idGeneratorService;

@GetMapping("/generate-id")

public long generateId() {

return idGeneratorService.generateId();

}

}

```

4. 配置 workerId

在分布式系统中,`workerId` 需要唯一,可以通过配置文件或机器标识动态分配。例如,使用 Spring Boot 的 `application.properties`:

```properties

snowflake.worker-id=1

```

然后在服务中读取:

```java

@Service

public class IdGeneratorService {

private final SnowflakeIdGenerator idGenerator;

@Autowired

public IdGeneratorService(@Value("${snowflake.worker-id}") long workerId) {

this.idGenerator = new SnowflakeIdGenerator(workerId);

}

public long generateId() {

return idGenerator.nextId();

}

}

```


使用第三方库

如果你不想自己实现雪花算法,可以使用现成的库,例如:

  • **Hutool**:一个流行的 Java 工具库,内置了雪花算法实现。

```xml

<dependency>

<groupId>cn.hutool</groupId>

<artifactId>hutool-all</artifactId>

<version>5.8.11</version>

</dependency>

```

使用示例:

```java

import cn.hutool.core.lang.Snowflake;

Snowflake snowflake = new Snowflake(1, 1); // workerId, dataCenterId

long id = snowflake.nextId();

```

  • **MyBatis-Plus**:如果你的项目使用 MyBatis-Plus,它也提供了雪花算法的支持。

注意事项

  1. **时钟回拨问题**:如果服务器时间被调整,可能导致 ID 重复。需要在代码中处理时钟回拨。

  2. **机器 ID 分配**:在分布式环境中,确保每个节点的 `workerId` 唯一。

  3. **性能**:雪花算法适合高并发场景,但序列号耗尽后需等待下一毫秒。

希望这个解答对你有帮助!如果需要更详细的代码或优化建议,请告诉我。

相关推荐
Postkarte不想说话1 分钟前
JSON序列化与反序列化-----使用JSON for Modern C++库
后端
Re2752 分钟前
springboot源码分析--初始加载配置类
java·spring boot
五行星辰3 分钟前
SpringBoot集成Log4j2终极指南:从基础配置到性能调优
java·后端
Fw9965319 分钟前
Spring如何解决获取到不完整Bean的问题
后端
快来卷java27 分钟前
深入剖析 JVM:从组成原理到调优实践
java·jvm·spring boot·spring cloud·数据挖掘·maven
Aska_Lv35 分钟前
springboot-tomcat 线程处理web接口解读
后端
苏三说技术37 分钟前
千万级大表的优化技巧
后端
天上掉下来个程小白42 分钟前
Redis-06.Redis常用命令-列表操作命令
java·redis·后端·springboot·苍穹外卖
掘金码甲哥1 小时前
双份请求,双倍快乐
后端
宦如云1 小时前
PHP语言的分布式账本
开发语言·后端·golang