Loading...
墨滴

远方聂努达

2021/11/26  阅读:45  主题:极简黑

Mybatis-plus 自定义id生成器

Mybatis-Plus 自定义 id 生成器

信仰与梦

近期在学习 Mybatis-Plus 的过程中,一点自己的小总结。

Mybatis-Plus 生成 ID 类型有以下几种方式:


    /**
     * 数据库ID自增
     * <p>该类型请确保数据库设置了 ID自增 否则无效</p>
     */

    AUTO(0),
    /**
     * 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
     */

    NONE(1),
    /**
     * 用户输入ID
     * <p>该类型可以通过自己注册自动填充插件进行填充</p>
     */

    INPUT(2),

    /* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
    /**
     * 分配ID (主键类型为number或string),
     * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(雪花算法)
     *
     * @since 3.3.0
     */

    ASSIGN_ID(3),
    /**
     * 分配UUID (主键类型为 string)
     * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))
     */

    ASSIGN_UUID(4);

在这里我使用的是:

@TableId(type = IdType.NONE)
    private Long id;

自定义 ID 生成器代码如下:

/**
 * 自定义ID生成器
 *
 * @author Greenarrow
 */
@Slf4j
@Component
public class CustomIdGenerator implements IdentifierGenerator {


    private static final int TOTAL_BITS = 64;
    private static final int EPOCH_BITS = 42;
    private static final int NODE_ID_BITS = 10;
    private static final int SEQUENCE_BITS = 12;
    private static final int MAXNODEID = (int) (Math.pow(2, NODE_ID_BITS) - 1);
    private static final int MAXSEQUENCE = (int) (Math.pow(2, SEQUENCE_BITS) - 1);
    /**
     * 自定义Epoch,格林威治时间为 2015-01-01 00:00:00 北京时间为 2015-01-01 08:00:00
     */
    private static final long CUSTOM_EPOCH = 1420070400000L;

    private volatile long sequence = 0L;
    private volatile long lastTimestamp = -1L;

    private final int globalNodeId;
    private final AtomicLong al = new AtomicLong(1);

    public CustomIdGenerator() {
        this.globalNodeId = createNodeId();
    }
    @Override
    public Long nextId(Object entity) {
        long currentTimestamp = timestamp();
        if (currentTimestamp < lastTimestamp) {
            throw new IllegalStateException("无效的系统时钟!");
        }
        if (currentTimestamp == lastTimestamp) {
            sequence = (sequence + 1) & MAXSEQUENCE;

            // 代表序列已用尽,等待下一个毫秒
            if (sequence == 0) {
                currentTimestamp = waitNextMillis(currentTimestamp);
            }
        } else {
            sequence = 0;
        }
        lastTimestamp = currentTimestamp;
        long id = currentTimestamp << (TOTAL_BITS - EPOCH_BITS);
        id |= (globalNodeId << (TOTAL_BITS - EPOCH_BITS - NODE_ID_BITS));
        id |= sequence;
        return id;
    }

    private static long timestamp() {
        return Instant.now().toEpochMilli() - CUSTOM_EPOCH;
    }

    /**
     * 等待到下一个毫秒
     *
     * @param currentTimestamp 当前时间戳
     * @return
     */
    private long waitNextMillis(long currentTimestamp) {
        while (currentTimestamp == lastTimestamp) {
            currentTimestamp = timestamp();
        }
        return currentTimestamp;
    }


    /**
     * 创建集群节点编号
     *
     * @return
     */
    private int createNodeId() {
        int nodeId;
        try {
            StringBuilder stringBuilder = new StringBuilder();
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            while (networkInterfaces.hasMoreElements()) {
                NetworkInterface networkInterface = networkInterfaces.nextElement();
                byte[] macAddress = networkInterface.getHardwareAddress();
                if (macAddress != null) {
                    for (int i = 0; i < macAddress.length; i++) {
                        stringBuilder.append(String.format("%02X", macAddress[i]));
                    }
                }
            }
            nodeId = stringBuilder.toString().hashCode();
        } catch (Exception e) {
            nodeId = (new SecureRandom().nextInt());
        }
        nodeId = nodeId & MAXNODEID;
        return nodeId;
    }

}

恋爱与死

测试结果如下:

都是上好的麻醉

- END -

远方聂努达

2021/11/26  阅读:45  主题:极简黑

作者介绍

远方聂努达