话不多说,直接上代码
代码
POM
<!-- Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- MySQL驱动 --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><!-- MybatisPlus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.9</version></dependency><!-- Redisson --><dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.39.0</version></dependency>
自定义ID生成器
import java.util.concurrent.TimeUnit;import org.redisson.api.RAtomicLong;import org.redisson.api.RLock;import org.redisson.api.RedissonClient;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.scheduling.annotation.EnableScheduling;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;import com.baomidou.mybatisplus.core.toolkit.Sequence;import jakarta.annotation.Resource;import lombok.extern.slf4j.Slf4j;@Slf4j@EnableScheduling@Componentpublic class SnowflakeIdGenerator implements IdentifierGenerator {@Resourceprivate RedissonClient redissonClient;@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic Number nextId(Object entity) {return getSequence().nextId();}private volatile Sequence sequence;private Long id;public Sequence getSequence() {if (sequence == null) {synchronized (SnowflakeIdGenerator.class) {if (sequence == null) {RLock lock = redissonClient.getLock("snowflake:lock");try {if (lock.tryLock(10, 10, TimeUnit.SECONDS)) {RAtomicLong atomicLong = redissonClient.getAtomicLong("snowflake:id");// 最终获取的序号IDlong id;// 累计获取的次数int i = 0;do {i++;// 如果累计获取超过1024次,则说明没有可以使用的ID了,抛出异常if (i > 1024) {log.error("获取不到可以使用的雪花ID序号");throw new RuntimeException("获取不到可以使用的雪花ID序号");}// 获取IDid = atomicLong.incrementAndGet();if (id >= 1024) {id = 0;atomicLong.set(0);}// 检查是否已被占用String watchDogKey = "snowflake:id:" + id;if (stringRedisTemplate.hasKey(watchDogKey)) {log.warn("当前雪花ID序号:{}已被使用", id);} else {// 未使用,设置占用标记stringRedisTemplate.opsForValue().set(watchDogKey, "", 65, TimeUnit.SECONDS);this.id = id;break;}} while (true);long workerId = id / 32;long datacenterId = id % 32;log.info("当前雪花ID序号为:{},对应的workerId为:{},对应的datacenterId为:{}", id, workerId, datacenterId);sequence = new Sequence(workerId, datacenterId);}} catch (InterruptedException e) {throw new RuntimeException(e);} finally {if (lock.isLocked() && lock.isHeldByCurrentThread()) {lock.unlock();log.debug("lock released");}}}}}return sequence;}@Scheduled(fixedDelay = 20000)public void scheduledTask() {if (id == null) {log.debug("雪花ID序号未初始化,无需执行");return;}// 更新占用stringRedisTemplate.opsForValue().set("snowflake:id:" + id, "", 65, TimeUnit.SECONDS);}}
测试
实体
import java.io.Serializable;import com.baomidou.mybatisplus.annotation.IdType;import com.baomidou.mybatisplus.annotation.TableId;import com.baomidou.mybatisplus.annotation.TableName;import com.baomidou.mybatisplus.extension.activerecord.Model;import lombok.Getter;import lombok.NoArgsConstructor;import lombok.Setter;import lombok.ToString;import lombok.experimental.Accessors;/*** 示例** @author Max_Qiu*/@Getter@Setter@NoArgsConstructor@ToString@Accessors(chain = true)@TableName("demo")public class Demo extends Model<Demo> {/*** 主键ID*/@TableId(value = "id", type = IdType.ASSIGN_ID)private Long id;@Overridepublic Serializable pkVal() {return this.id;}}
测试类
import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;import org.junit.jupiter.api.Test;import org.springframework.boot.test.context.SpringBootTest;import com.maxqiu.demo.entity.Demo;/*** @author Max_Qiu*/@SpringBootTestclass DemoServiceTest {@Testvoid insert() throws InterruptedException {ExecutorService executorService = Executors.newCachedThreadPool();for (int i = 0; i < 3; i++) {executorService.execute(() -> {Demo demo = new Demo();demo.insert();System.out.println(demo.getId());});}executorService.shutdown();executorService.awaitTermination(5, TimeUnit.SECONDS);}}
输出
2024-12-15T18:58:00.882+08:00 INFO 15392 --- [pool-2-thread-3] c.m.demo.config.SnowflakeIdGenerator : 当前雪花ID序号为:26,对应的workerId为:0,对应的datacenterId为:262024-12-15T18:58:00.902+08:00 INFO 15392 --- [pool-2-thread-3] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...2024-12-15T18:58:01.074+08:00 INFO 15392 --- [pool-2-thread-3] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@9706daa2024-12-15T18:58:01.076+08:00 INFO 15392 --- [pool-2-thread-3] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.186824914365867622718682491436586762281868249143658676226
	声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。



评论(0)