欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JAVA實現(xiàn)生成順序ID,不浪費ID

 更新時間:2024年04月15日 10:11:37   作者:不禿頭灬程序猿  
這篇文章主要介紹了JAVA實現(xiàn)生成順序ID,不浪費ID問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

JAVA實現(xiàn)生成順序ID

 public Integer buildEmseId() {
        QueryWrapper<UseInfo> queryWrapper = new QueryWrapper<>();
        List<UseInfo> emseInfoList = emseInfoMapper.selectList(queryWrapper);
        List<Integer> list = new ArrayList<>();
        for (EmseInfo mad:emseInfoList) {
            list.add(mad.getEmseId());
        }
 
        int buildEmseId = 1;
        if(list.size()>0){
            boolean[] emseBoolean =new boolean[256];
            for (int emseId : list) {
                if (emseId >= emseBoolean.length || emseId < 0) {
                    continue;
                }
                emseBoolean[emseId] = true;
            }
            for(int i = 1; i < emseBoolean.length; i++){
                if(!emseBoolean[i]){
                    buildEmseId = i;
                    break;
                }
            }
            log.info("emseId=" + buildEmseId);
        }
        return buildEmseId;
    }
}

大概寫了一下,之前有個需求是在存主鍵的時候不能浪費ID去存,比如數(shù)據(jù)庫中id目前是1,2,3,5,6,很明顯id是4的記錄被刪除了,正常我們新增一條會從7開始,但需求不能浪費id,此時新增必須是4。

但這種有個限制條件,id不是無限自增的,我這里最大是255.

這個方法會校驗缺失的id并進行生成,如果沒有缺失,就會按順序生成。

一般可能沒這種離譜需求。。

JAVA生成id方式

雪花算法生成id

啟動類

(關(guān)于后端id為Long類型造成的精度丟失問題,前端用bigNumber的類型,可以處理長整數(shù),也可避免此問題)

/**
     * 雪花算法.
     *
     * @param dataSource
     * @param environment
     * @return
     */
    @Bean
    public TwitterSnowflakeIdGenerator twitterSnowflakeIdGenerator(DataSource dataSource, Environment environment) {
        return TwitterSnowflakeIdGenerator.createInstance(dataSource, environment.getProperty("spring.application.name"));
    }

    /**
     * 轉(zhuǎn)化long類型為String,處理前后端精度問題.
     * @return
     */
    @Bean("jackson2ObjectMapperBuilderCustomizer")
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.serializerByType(Long.class, ToStringSerializer.instance)
                .serializerByType(Long.TYPE, ToStringSerializer.instance);
    }

配置類

package com.mn.common.utils;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.Assert;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 基于Twitter/snowflake 算法的分布式全局id生成器 64位ID (42(毫秒)+10位(統(tǒng)一分配的業(yè)務(wù)號workerIdBits)+12(重復(fù)累加))
 * 
 * 整體上按照時間自增排序,并且整個分布式系統(tǒng)內(nèi)不會產(chǎn)生ID碰撞(由datacenter和機器ID作區(qū)分), 并且效率較高,經(jīng)測試,snowflake每秒能夠產(chǎn)生26萬ID左右,完全滿足需要。
 * 
 * @author xuwei
 * @date 2021年9月27日
 * @version 1.0
 */
public final class TwitterSnowflakeIdGenerator {

    private final static long twepoch = 1288834974657L;
    // 機器標識位數(shù)
    private final static long workerIdBits = 10L;
    // 機器ID最大值
    private final static long maxWorkerId = ~(-1L << workerIdBits);

    // 毫秒內(nèi)自增位
    private final static long sequenceBits = 12L;
    // 機器ID偏左移12位
    private final static long workerIdShift = sequenceBits;

    // 時間毫秒左移22位
    private final static long timestampLeftShift = sequenceBits + workerIdBits;

    private final static long sequenceMask = ~(-1L << sequenceBits);

    private long lastTimestamp = -1L;

    private long sequence = 0L;
    private final long workerId; // 此workId通過集中產(chǎn)生

    private static TwitterSnowflakeIdGenerator generator = null;

    /**
     * @param ds 包含sys_set的數(shù)據(jù)源
     * @param webDisplayName,web的上下文路徑,即web.xml里面的displayName
     * @return
     */
    public static TwitterSnowflakeIdGenerator createInstance(DataSource ds, String webDisplayName) {
        if (generator == null) {
            synchronized (TwitterSnowflakeIdGenerator.class) {
                if (generator == null) {
                    long wId = getWorkerId(ds, webDisplayName);
                    if (wId == -1L)
                        return null;
                    generator = new TwitterSnowflakeIdGenerator(wId);
                }
            }
        }
        return generator;
    }

    private static long getWorkerId(DataSource ds, String webDisplayName) {
        long wId = -1L;
        try {
            // 獲取主機名

            String hostname = NetworkUtil.getFirstIp();
            /*
             * InitialContext initialContext = new InitialContext(); DataSource ds =
             * (DataSource)initialContext.lookup(dbJndiName);
             */
            JdbcTemplate t = new JdbcTemplate(ds);
            // 主機名+web.xml里面的displayName,這個目前是唯一不變的,由它來決定唯一號,保存在SYS_SET表中
            // 命名規(guī)則為 主機名_displayName_id
            String key = hostname + "_" + webDisplayName + "_id";
            List<Map<String, Object>> list = t.queryForList("select svalue from sys_set where skey = ?", key);
            if (list.isEmpty()) {// 數(shù)據(jù)庫沒有這個記錄
                // 這兩個地方需要事務(wù),暫不加
                List<Map<String, Object>> list2 = t.queryForList(
                        "select svalue from sys_set where status = 1 and class = ? order by sort", "ID_GENERATOR");
                boolean found = false;
                for (int i = 0; i < list2.size(); i++) {
                    Map<String, Object> map = list2.get(i);
                    if (map != null) {
                        int value = Integer.parseInt(map.get("svalue").toString());
                        if (value == i + 1) {
                            continue;
                        }
                        if (i < value) {// 找到一個小值,占用這個值
                            wId = i + 1;
                            t.update(
                                    "insert into sys_set(skey,sname,svalue,sort,status,class,remark,time_update) "
                                            + "values(?,'id_generator',?,?,1,'ID_GENERATOR','',current_timestamp)",
                                    key, wId, wId);// 插入數(shù)據(jù)庫中
                            found = true;
                            break;
                        }
                    }
                }
                if (!found) {
                    wId = list2.size() + 1;
                    t.update(
                            "insert into sys_set(skey,sname,svalue,sort,status,class,remark,time_update) "
                                    + "values(?,'id_generator',?,?,1,'ID_GENERATOR','',current_timestamp)",
                            key, wId, wId);// 插入數(shù)據(jù)庫中
                }
            } else {
                wId = Long.parseLong(list.get(0).get("svalue").toString());
            }
        } catch (Exception e) {
            // Auto-generated catch block
            e.printStackTrace();
        }

        return wId;
    }

    /**
     * @param workerId - 機器ID,范圍[0,1024]
     */
    private TwitterSnowflakeIdGenerator(long workerId) {
        Assert.isTrue(workerId <= maxWorkerId && workerId >= 0, "worker Id can't be greater than %d or less than 0");
        this.workerId = workerId;
    }

    public synchronized Long nextId() {
        return getNextId();
    }

    public List<Long> nextIds(int batchSize) {
        synchronized (TwitterSnowflakeIdGenerator.class) {
            Assert.isTrue(batchSize > 1, "worker Id can't be less than 1");
            List<Long> list = new ArrayList<>((int) (batchSize * 1.2));
            for (int i = 0; i < batchSize; i++) {
                list.add(getNextId());
            }
            return list;
        }
    }

    private long getNextId() {
        long timestamp = timeGen();
        if (timestamp < lastTimestamp) {
            try {
                throw new Exception("Clock moved backwards.  Refusing to generate id for " + (lastTimestamp - timestamp)
                        + " milliseconds");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        if (lastTimestamp == timestamp) {
            // 當(dāng)前毫秒內(nèi),則+1
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                // 當(dāng)前毫秒內(nèi)計數(shù)滿了,則等待下一秒
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0;
        }
        lastTimestamp = timestamp;
        // ID偏移組合生成最終的ID,并返回ID
        return ((timestamp - twepoch) << timestampLeftShift) | (workerId << workerIdShift) | sequence;
    }

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

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

}

package com.mn.common.utils;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

public class NetworkUtil {
    
    private NetworkUtil() {
        
    }
    
    public static boolean internalIp(byte[] addr) {
        final byte b0 = addr[0];
        final byte b1 = addr[1];
        // 10.x.x.x/8
        final byte SECTION_1 = 0x0A;
        // 172.16.x.x/12
        final byte SECTION_2 = (byte) 0xAC;
        final byte SECTION_3 = (byte) 0x10;
        final byte SECTION_4 = (byte) 0x1F;
        // 192.168.x.x/16
        final byte SECTION_5 = (byte) 0xC0;
        final byte SECTION_6 = (byte) 0xA8;
        switch (b0) {
            case SECTION_1:
                return true;
            case SECTION_2:
                if (b1 >= SECTION_3 && b1 <= SECTION_4) {
                    return true;
                }
            case SECTION_5:
                if(b1 == SECTION_6) {
                    return true;
                }
//                switch (b1) {
//                    case SECTION_6:
//                        return true;
//                    default:
//                        break;
//                }
            default:
                return false;
        }
    }

    // 獲取第一個內(nèi)網(wǎng)地址
    public static String getFirstIp() {
        String ipAddress = "";
        try {
            Enumeration<NetworkInterface> interfaces;
            interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface ni = interfaces.nextElement();
                Enumeration<InetAddress> addresss = ni.getInetAddresses();
                while (addresss.hasMoreElements()) {
                    InetAddress nextElement = addresss.nextElement();
                    nextElement.isLoopbackAddress();
                    String hostAddress = nextElement.getHostAddress();
                    if (nextElement instanceof Inet4Address) { // 只關(guān)心 IPv4 地址
                        boolean isIn = internalIp(nextElement.getAddress());
                        if (isIn) {// 是內(nèi)網(wǎng)地址
                            return hostAddress;
                        }
                        System.out.println("網(wǎng)卡接口地址:" + nextElement.getHostAddress());
                        System.out.println("網(wǎng)卡接口地址:" + isIn);
                        // 判斷能否到達數(shù)據(jù)庫,如果能到達,選這個
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();

        }
        return ipAddress;
    }
}

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論