分布式之全局主键

在应用中,我们通常需要对各个项目中的各个库表的主键进行统一的获取分配,一般来说,我们会将此项目注册到Eureka上面,供其他项目有入库操作时调用,此处仅为了演示,所以没有将其注册到Eureka

 pom.xml文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.yj</groupId>
	<artifactId>IdCenter</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>IdCenter</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.17.RELEASE</version>
		<relativePath />
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.8.1</version>
		</dependency>
	</dependencies>
</project>

GlobalIdController

package com.yj.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.yj.exception.BusinessException;
import com.yj.service.CreateGlobalIdService;

@Controller
public class GlobalIdController {

	@Autowired
	private CreateGlobalIdService createGlobalIdService;

	@RequestMapping(value = "/createGlobalId", method = RequestMethod.GET)
	@ResponseBody
	public Object createGlobalId() {
		String result = null;
		try {
			result = createGlobalIdService.getId();
		} catch (BusinessException e) {
			e.printStackTrace();
		}
		return result;
	}
}

CreateGlobalIdService

package com.yj.service;

import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.yj.util.IdWorker;

@Service
public class CreateGlobalIdService {

	@Value("${dataCenterId}")
	private Integer dataCenterId;
	@Value("${workId}")
	private Integer workId;

	private static final Map<String, IdWorker> workMap = new HashMap<String, IdWorker>();

	public String getId() {
		IdWorker idWorker = workMap.get(dataCenterId + "_" + workId);
		if (idWorker != null) {
			return StringUtils.leftPad(Long.toHexString(idWorker.nextId()), 16, "0");
		}
		idWorker = new IdWorker(dataCenterId, workId);
		workMap.put(dataCenterId + "_" + workId, idWorker);
		return StringUtils.leftPad(Long.toHexString(idWorker.nextId()), 16, "0");
	}
}

IdWorker

package com.yj.util;

public class IdWorker {
	// 主机编号
	private long workerId;
	// 机房编号
	private long datacenterId;
	private long sequence = 0L;
	// 正式运行之日,重新计算一个新值
	private static long twepoch = 1444721918651L;
	// 机器标识位数
	private long workerIdBits = 5L;
	// 数据中心标识位数
	private long datacenterIdBits = 5L;
	// 主机编号(从0开始的序列)最大值
	private long maxWorkerId = -1L ^ (-1L << workerIdBits);
	// 机房编号(从0开始的序列)最大值
	private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
	// 毫秒内自增位
	private long sequenceBits = 12L;
	// 机器ID偏左移12位
	private long workerIdShift = sequenceBits;
	// 数据中心ID左移17位
	private long datacenterIdShift = sequenceBits + workerIdBits;
	// 时间毫秒左移22位
	private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
	private long sequenceMask = -1L ^ (-1L << sequenceBits);

	private long lastTimestamp = -1L;

	public IdWorker(long datacenterId, long workerId) {
		if (workerId > maxWorkerId || workerId < 0) {
			throw new IllegalArgumentException(
					String.format("workerId can't be greater than %d or less than 0", maxWorkerId));
		}
		if (datacenterId > maxDatacenterId || datacenterId < 0) {
			throw new IllegalArgumentException(
					String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
		}
		this.workerId = workerId;
		this.datacenterId = datacenterId;
	}

	public synchronized long nextId() {
		long timestamp = this.timeGen();
		if (this.lastTimestamp == timestamp) {
			this.sequence = (this.sequence + 1) & sequenceMask;
			if (this.sequence == 0) {
				timestamp = this.tilNextMillis(this.lastTimestamp);
			}
		} else {
			this.sequence = 0;
		}
		if (timestamp < this.lastTimestamp) {
			try {
				throw new Exception(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds",
						this.lastTimestamp - timestamp));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		this.lastTimestamp = timestamp;
		long nextId = ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift)
				| (workerId << workerIdShift) | sequence;
		return nextId;
	}

	private long tilNextMillis(final long lastTimestamp) {
		long timestamp = this.timeGen();
		while (timestamp <= lastTimestamp) {
			timestamp = this.timeGen();
		}
		return timestamp;
	}

	private long timeGen() {
		return System.currentTimeMillis();
	}
}

application.properties

server.port=80
dataCenterId=0
workId=0

我们启动此项目,然后访问

http://127.0.0.1/createGlobalId

获取到了全局ID:05f5596975000000

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猎户星座。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值