zoukankan      html  css  js  c++  java
  • 百度开源的分布式 ID 生成器,太强大了!

    来源:https://lilinchao.com/archives/1226.html

    一、UidGenerator是什么

    UidGenerator是百度开源的一款分布式高性能的唯一ID生成器,是基于snowflake模型的一种ID生成器

    二、UidGenerator的优势

    1. 解决了时钟回调的问题
    2. 使用ringbuffer,无锁进行id的生产与消费,速度非常快
    3. 适用于多线程,不会有单线程瓶颈

    三、整合

    本次通过SpringBoot2.x和MyBatis对百度UidGenerator进行整合。

    3.1 UidGenerator引入

    一般使用两种方式引入UidGenerator:

    1)从官网下载源码作为自己项目的一个Module引入到项目中

    官网地址:https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md

    2)互联网jar包引入(本文采取的是该种方式)

    因为UidGenerator自带引入了mybatis,和自己项目有冲突的可以进行排除

    <dependency>
        <groupId>com.xfvape.uid</groupId>
        <artifactId>uid-generator</artifactId>
        <version>0.0.4-RELEASE</version>
    </dependency>
    

    排除冲突依赖

    uid-generator中依赖了logback和mybatis。一般在项目搭建过程中,springboot中已经有了logback依赖,mybatis会作为单独的依赖引入。如果版本和uid-generator中的依赖不一致的话,就会导致冲突。

    排除冲突的依赖如下:

    <dependency>
        <groupId>com.xfvape.uid</groupId>
        <artifactId>uid-generator</artifactId>
        <version>0.0.4-RELEASE</version>
        <exclusions>
             <exclusion>
                 <groupId>org.slf4j</groupId>
                 <artifactId>log4j-over-slf4j</artifactId>
             </exclusion>
             <exclusion>
                 <groupId>ch.qos.logback</groupId>
                 <artifactId>logback-classic</artifactId>
             </exclusion>
             <exclusion>
                 <groupId>org.slf4j</groupId>
                 <artifactId>slf4j-api</artifactId>
             </exclusion>
              <exclusion>
                 <groupId>org.mybatis</groupId>
                 <artifactId>mybatis-spring</artifactId>
             </exclusion>
             <exclusion>
                 <groupId>org.mybatis</groupId>
                 <artifactId>mybatis</artifactId>
             </exclusion>
        </exclusions>
    </dependency>
    

    3.2 创建表

    在 MySQL数据库中建一个名为 WORKER_NODE的数据表,其 sql如下:

    CREATE TABLE WORKER_NODE
    (
    ID BIGINT NOT NULL AUTO_INCREMENT COMMENT 'auto increment id',
    HOST_NAME VARCHAR(64) NOT NULL COMMENT 'host name',
    PORT VARCHAR(64) NOT NULL COMMENT 'port',
    TYPE INT NOT NULL COMMENT 'node type: ACTUAL or CONTAINER',
    LAUNCH_DATE DATE NOT NULL COMMENT 'launch date',
    MODIFIED TIMESTAMP NOT NULL COMMENT 'modified time',
    CREATED TIMESTAMP NOT NULL COMMENT 'created time',
    PRIMARY KEY(ID)
    )
     COMMENT='DB WorkerID Assigner for UID Generator',ENGINE = INNODB;
    

    建表时可能会报错,原因是该建表语句定义了两个TIMESTAMP字段,因为mysql 低版本控制比较严格

    解决办法:

    方式一:

    直接把TIMESTAMP改成DATETIME 即可

    方式二:

    建表前先设置sql_mode:

    set sql_mode="NO_ENGINE_SUBSTITUTION";
    

    3.3 将uid-generator核心对象装配为spring的bean

    uid-generator提供了两种生成器: DefaultUidGenerator、CachedUidGenerator。如对UID生成性能有要求, 请使用CachedUidGenerator。

    @Configuration
    public class WorkerNodeConfig {
    
        @Bean("disposableWorkerIdAssigner")
        public DisposableWorkerIdAssigner disposableWorkerIdAssigner(){
            DisposableWorkerIdAssigner disposableWorkerIdAssigner = new DisposableWorkerIdAssigner();
            return  disposableWorkerIdAssigner;
        }
    
        @Bean("cachedUidGenerator")
        public UidGenerator uidGenerator(DisposableWorkerIdAssigner disposableWorkerIdAssigner){
            CachedUidGenerator cachedUidGenerator = new CachedUidGenerator();
            cachedUidGenerator.setWorkerIdAssigner(disposableWorkerIdAssigner);
            return cachedUidGenerator;
        }
    }
    

    直接创建WorkerNodeConfig类,复制以上代码。

    3.4 重写WorkerIdAssigner接口

    public class DisposableWorkerIdAssigner implements WorkerIdAssigner {
    
        @Resource
        private WorkerNodeMapper workerNodeMapper;
        @Override
        @Transactional
        public long assignWorkerId() {
            WorkerNode workerNode = buildWorkerNode();
    
            workerNodeMapper.addWorkerNode(workerNode);
    
            return workerNode.getId();
        }
    
        private WorkerNode buildWorkerNode() {
            WorkerNode workNode = new WorkerNode();
            if (DockerUtils.isDocker()) {
                workNode.setType(WorkerNodeType.CONTAINER.value());
                workNode.setHostName(DockerUtils.getDockerHost());
                workNode.setPort(DockerUtils.getDockerPort());
                workNode.setLaunchDate(new Date());
            } else {
                workNode.setType(WorkerNodeType.ACTUAL.value());
                workNode.setHostName(NetUtils.getLocalAddress());
                workNode.setPort(System.currentTimeMillis() + "-" + RandomUtils.nextInt(100000));
                workNode.setLaunchDate(new Date());
            }
    
            return workNode;
        }
    }
    

    创建一个DisposableWorkerIdAssigner类直接复制以上代码。

    3.5 引入WorkerNodeMapper.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.uidgenerator.mapper.WorkerNodeMapper">
      <resultMap id="BaseResultMap"
                 type="com.uidgenerator.entity.WorkerNode">
        <id column="ID" jdbcType="BIGINT" property="id" />
        <result column="HOST_NAME" jdbcType="VARCHAR" property="hostName" />
        <result column="PORT" jdbcType="VARCHAR" property="port" />
        <result column="TYPE" jdbcType="INTEGER" property="type" />
        <result column="LAUNCH_DATE" jdbcType="DATE" property="launchDate" />
        <result column="MODIFIED" jdbcType="TIMESTAMP" property="modified" />
        <result column="CREATED" jdbcType="TIMESTAMP" property="created" />
      </resultMap>
    
      <insert id="addWorkerNode" useGeneratedKeys="true" keyProperty="id"
              parameterType="com.uidgenerator.entity.WorkerNode">
            INSERT INTO WORKER_NODE
            (HOST_NAME,
             PORT,
             TYPE,
             LAUNCH_DATE,
             MODIFIED,
             CREATED)
            VALUES (
              #{hostName},
              #{port},
              #{type},
              #{launchDate},
              NOW(),
              NOW())
        </insert>
    
      <select id="getWorkerNodeByHostPort" resultMap="BaseResultMap ">
            SELECT
                ID,
                HOST_NAME,
                PORT,
                TYPE,
                LAUNCH_DATE,
                MODIFIED,
                CREATED
            FROM
                WORKER_NODE
            WHERE
                HOST_NAME = #{host} AND PORT = #{port}
        </select>
    </mapper>
    

    可以通过mybatis生成工具直接生成文件和实体类,然后将插入和查询方法复制

    注意修改resultMap中的type和insert中的keyProperty为自身项目的实体类地址

    在application.yml文件中增加如下配置

    mybatis:
      mapper-locations: classpath:mybatis/*.xml
    

    3.6实体类

    使用插件生成的实体类

    3.7创建Mapper

    @Mapper
    public interface WorkerNodeMapper {
    
        int addWorkerNode(WorkerNode workerNodeEntity);
    
    	WorkerNode getWorkerNodeByHostPort(@Param("host") String host, @Param("port") String port);
    
    }
    

    3.8 Service

    IWorkerNodeService接口

    public interface IWorkerNodeService {
        public long genUid();
    }
    

    WorkerNodeServiceImpl实现类

    @Service
    public class WorkerNodeServiceImpl implements IWorkerNodeService {
        @Resource
        private UidGenerator uidGenerator;
    
        @Override
        public long genUid() {
            Long uu_id = UidGeneratorComponent.uu_id;
            return uidGenerator.getUID();
        }
    }
    

    3.8 Controller

    @RestController
    public class WorkerNodeServiceController {
        @Resource
        private IWorkerNodeService workerNodeService;
        /**
         * 集成百度uid-generator生成id
         * @return
         */
        @GetMapping("/baidu/uid")
        public long baiduUid(){
            long uid = workerNodeService.genUid();
            return uid;
        }
    }
    

    3.9 访问接口测试

    http://127.0.0.1:8099/test/baidu/uid

    项目目录结构

    近期热文推荐:

    1.600+ 道 Java面试题及答案整理(2021最新版)

    2.终于靠开源项目弄到 IntelliJ IDEA 激活码了,真香!

    3.阿里 Mock 工具正式开源,干掉市面上所有 Mock 工具!

    4.Spring Cloud 2020.0.0 正式发布,全新颠覆性版本!

    5.《Java开发手册(嵩山版)》最新发布,速速下载!

    觉得不错,别忘了随手点赞+转发哦!

  • 相关阅读:
    CSDN文章列表的CSS实现
    Arcgis for Js之鼠标经过显示对象名的实现
    Java ssh 访问windows/Linux
    HTTP长连接实现“服务器推”的技术
    Eclipse设置、调优、使用
    Quartz的配置文件quartz.properties详解
    Quartz所使用的表的说明
    Quartz动态添加、修改和删除定时任务
    Quartz的misfire特性
    项目中使用Quartz集群分享--转载
  • 原文地址:https://www.cnblogs.com/javastack/p/14856622.html
Copyright © 2011-2022 走看看