关于java:百度开源的分布式-ID-生成器太强大了

38次阅读

共计 5710 个字符,预计需要花费 15 分钟才能阅读完成。

起源:https://lilinchao.com/archive…

一、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-…

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/ba…

我的项目目录构造

近期热文举荐:

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

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

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

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

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

感觉不错,别忘了顺手点赞 + 转发哦!

正文完
 0