深圳本地做網(wǎng)站網(wǎng)絡(luò)營銷的策略包括
/*** @author lwh* @date 2023/9/5* @description 批量插入,手動設(shè)置**/
public class IdWorker {//因為二進制里第一個 bit 為如果是 1,那么都是負(fù)數(shù),但是我們生成的 id 都是正數(shù),所以第一個 bit 統(tǒng)一都是 0。//機器ID 2進制5位 32位減掉1位 31個private long workerId;//機房ID 2進制5位 32位減掉1位 31個private long datacenterId;//代表一毫秒內(nèi)生成的多個id的最新序號 12位 4096 -1 = 4095 個private long sequence;//設(shè)置一個時間初始值 2^41 - 1 差不多可以用69年private long twepoch = 1585644268888L;//5位的機器idprivate long workerIdBits = 5L;//5位的機房idprivate long datacenterIdBits = 5L;//每毫秒內(nèi)產(chǎn)生的id數(shù) 2 的 12次方private long sequenceBits = 12L;// 這個是二進制運算,就是5 bit最多只能有31個數(shù)字,也就是說機器id最多只能是32以內(nèi)private long maxWorkerId = -1L ^ (-1L << workerIdBits);// 這個是一個意思,就是5 bit最多只能有31個數(shù)字,機房id最多只能是32以內(nèi)private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);private long workerIdShift = sequenceBits;private long datacenterIdShift = sequenceBits + workerIdBits;private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;private long sequenceMask = -1L ^ (-1L << sequenceBits);//記錄產(chǎn)生時間毫秒數(shù),判斷是否是同1毫秒private long lastTimestamp = -1L;public long getWorkerId(){return workerId;}public long getDatacenterId() {return datacenterId;}public long getTimestamp() {return System.currentTimeMillis();}public IdWorker(long workerId, long datacenterId, long sequence) {// 檢查機房id和機器id是否超過31 不能小于0if (workerId > maxWorkerId || workerId < 0) {throw new IllegalArgumentException(String.format("worker Id 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;this.sequence = sequence;}// 這個是核心方法,通過調(diào)用nextId()方法,讓當(dāng)前這臺機器上的snowflake算法程序生成一個全局唯一的idpublic synchronized long nextId() {// 這兒就是獲取當(dāng)前時間戳,單位是毫秒long timestamp = timeGen();if (timestamp < lastTimestamp) {System.err.printf("clock is moving backwards. Rejecting requests until %d.", lastTimestamp);throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",lastTimestamp - timestamp));}// 下面是說假設(shè)在同一個毫秒內(nèi),又發(fā)送了一個請求生成一個id// 這個時候就得把seqence序號給遞增1,最多就是4096if (lastTimestamp == timestamp) {// 這個意思是說一個毫秒內(nèi)最多只能有4096個數(shù)字,無論你傳遞多少進來,//這個位運算保證始終就是在4096這個范圍內(nèi),避免你自己傳遞個sequence超過了4096這個范圍sequence = (sequence + 1) & sequenceMask;//當(dāng)某一毫秒的時間,產(chǎn)生的id數(shù) 超過4095,系統(tǒng)會進入等待,直到下一毫秒,系統(tǒng)繼續(xù)產(chǎn)生IDif (sequence == 0) {timestamp = tilNextMillis(lastTimestamp);}} else {sequence = 0;}// 這兒記錄一下最近一次生成id的時間戳,單位是毫秒lastTimestamp = timestamp;// 這兒就是最核心的二進制位運算操作,生成一個64bit的id// 先將當(dāng)前時間戳左移,放到41 bit那兒;將機房id左移放到5 bit那兒;將機器id左移放到5 bit那兒;將序號放最后12 bit// 最后拼接起來成一個64 bit的二進制數(shù)字,轉(zhuǎn)換成10進制就是個long型return ((timestamp - twepoch) << timestampLeftShift) |(datacenterId << datacenterIdShift) |(workerId << workerIdShift) | sequence;}/*** 當(dāng)某一毫秒的時間,產(chǎn)生的id數(shù) 超過4095,系統(tǒng)會進入等待,直到下一毫秒,系統(tǒng)繼續(xù)產(chǎn)生ID* @param lastTimestamp* @return*/private long tilNextMillis(long lastTimestamp) {long timestamp = timeGen();while (timestamp <= lastTimestamp) {timestamp = timeGen();}return timestamp;}//獲取當(dāng)前時間戳private long timeGen(){return System.currentTimeMillis();}/*** main 測試類* @param args*/public static void main(String[] args) {IdWorker worker = new IdWorker(1,1,1);for (int i = 0; i < 22; i++) {System.out.println(worker.nextId());}}
}
/*** @author lwh* @date 2023/9/5* @description**/
@Configuration
@Slf4j
public class SnowFlakeIdConfig {/*** @author lwh* @date 2023/9/5* @description 創(chuàng)建分布式ID對象**/@Beanpublic IdWorker idWorker() {Env env = ApolloInjector.getInstance(ConfigUtil.class).getApolloEnv();IdWorker idWorker = new IdWorker(getWorkId(), getDataCenterId(), 10);String msg = StrFormatter.format("【{}】IdWorker創(chuàng)建完成。WordId:{},DataCenterId:{}", env.name(), idWorker.getWorkerId(), idWorker.getDatacenterId());log.warn(msg);return idWorker;}/*** workId使用IP生成* @return workId*/private static Long getWorkId() {try {String hostAddress = Inet4Address.getLocalHost().getHostAddress();int[] ints = StringUtils.toCodePoints(hostAddress);int sums = 0;for (int b : ints) {sums = sums + b;}return (long) (sums % 32);}catch (UnknownHostException e) {// 失敗就隨機return RandomUtils.nextLong(0, 31);}}/*** dataCenterId使用hostName生成* @return dataCenterId*/private static Long getDataCenterId() {try {String hostName = SystemUtils.getHostName();int[] ints = StringUtils.toCodePoints(hostName);int sums = 0;for (int i: ints) {sums = sums + i;}return (long) (sums % 32);}catch (Exception e) {// 失敗就隨機return RandomUtils.nextLong(0, 31);}}
}
使用:
@Autowiredprivate IdWorker idWorker;// 根據(jù)訂單保存任務(wù)量scanTaskNumberList.stream().forEach(k -> k.setId(idWorker.nextId()));scanTaskNumberService.saveBatch(scanTaskNumberList);
集群部署下,動態(tài)生成雪花算法WorkId和DataCenterId_雪花 workerid-CSDN博客?
snowflake算法的workerId問題-騰訊云開發(fā)者社區(qū)-騰訊云