Baidu's open source distributed ID generator is too powerful!

Source: https://lilinchao.com/archives/1226.html

One, what is UidGenerator

UidGenerator is a distributed high-performance unique ID generator open sourced by Baidu. It is an ID generator based on the snowflake model.

Second, the advantages of UidGenerator

  1. Solved the problem of clock callback
  2. Use ringbuffer, lock-free production and consumption of id, very fast
  3. Suitable for multi-threading, there will be no single-threaded bottleneck

Three, integration

This time, Baidu UidGenerator was integrated through SpringBoot2.x and MyBatis.

3.1 UidGenerator introduction

There are generally two ways to introduce UidGenerator:

1) Download the source code from the official website and introduce it into the project as a Module of your own project

Official website address: https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md

2) Internet jar package introduction (this article adopts this method)

Because UidGenerator comes with mybatis, conflicts with your own project can be excluded

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

Eliminate conflict dependencies

uid-generator relies on logback and mybatis. Generally, in the process of project construction, there is already a logback dependency in springboot, and mybatis will be introduced as a separate dependency. If the version and the dependency in the uid-generator are inconsistent, it will cause a conflict.

The dependencies to exclude conflicts are as follows:

<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 Create a table

Built in a MySQL database called WORKER_NODEa data table, which sql as follows:

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;

An error may be reported when creating a table, because the statement to create a table defines two TIMESTAMP fields, because the MySQL version control is relatively strict

Solution:

method one:

Just change TIMESTAMP to DATETIME

Way two:

Set sql_mode before building the table:

set sql_mode="NO_ENGINE_SUBSTITUTION";

3.3 Assemble the uid-generator core object into a spring bean

uid-generator provides two generators: DefaultUidGenerator and CachedUidGenerator. If you have requirements for UID generation performance, please use 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;
    }
}

Create the WorkerNodeConfig class directly and copy the above code.

3.4 Rewrite the WorkerIdAssigner interface

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;
    }
}

Create a DisposableWorkerIdAssigner class and copy the above code directly.

3.5 Introduce 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>

You can directly generate files and entity classes through the mybatis generation tool, and then copy the insert and query methods

Pay attention to modify the type in the resultMap and the keyProperty in the insert to the entity class address of your own project

Add the following configuration in the application.yml file

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

3.6 Entity Class

Use the entity class generated by the plugin

3.7 Create Mapper

@Mapper
public interface WorkerNodeMapper {

    int addWorkerNode(WorkerNode workerNodeEntity);

    WorkerNode getWorkerNodeByHostPort(@Param("host") String host, @Param("port") String port);

}

3.8 Service

IWorkerNodeService interface

public interface IWorkerNodeService {
    public long genUid();
}

WorkerNodeServiceImpl implementation class

@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 Access interface test

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

Project directory structure

Recommended recent hot articles:

1. 600+ Java interview questions and answers compilation (2021 latest version)

2. Finally got the IntelliJ IDEA activation code by the open source project, it's so fragrant!

3. Ali Mock tool is officially open source, kill all Mock tools on the market!

4. Spring Cloud 2020.0.0 is officially released, a new disruptive version!

5. The latest release of "Java Development Manual (Songshan Edition)", download it quickly!

Feel good, don't forget to like + forward!