Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
话不多说,直接上代码 代码 POM org.springframework.boot spring-boot-starter-web </dep
话不多说,直接上代码
<!-- 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>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 { @Resource private RedissonClient redissonClient; @Resource private StringRedisTemplate stringRedisTemplate; @Override public 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"); // 最终获取的序号ID long id; // 累计获取的次数 int i = 0; do { i++; // 如果累计获取超过1024次,则说明没有可以使用的ID了,抛出异常 if (i > 1024) { log.error("获取不到可以使用的雪花ID序号"); throw new RuntimeException("获取不到可以使用的雪花ID序号"); } // 获取ID id = 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; @Override public 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 { @Test void 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