Snowflake algorithm implementation principle and accuracy failure problem

1. Implementation principle of snowflake algorithm

        The snowflake algorithm is a globally unique algorithm. It mainly appears in scenarios such as database sharding and table sharding as business primary keys, or as some ID generators such as order numbers. So in terms of global uniqueness, there are many implementation methods, such as UUID, Redis's atomic increment, the auto-increment ID of the global table of the database, etc. However, in actual applications, it also needs to meet the requirements of ordered increment, high performance, timestamp, etc.

        Snowflake Algorithm, as an algorithm for generating distributed globally unique ID, consists of a 64-bit long type number, which is divided into four parts.
①. In the first part, 1 bit is used to represent the sign bit, which is usually 0 (because the first bit is the sign bit, and because the id will not be a negative number, it is usually 0)
②, the second part, then use 41 bits to represent the timestamp in milliseconds, using the milliseconds of the system time
③. In the third part, 10 bits are used to record the working machine id, so that the uniqueness of the id generated on multiple servers can be guaranteed.
( If there is cross-computer room deployment, we can also divide it into two 5-bits. The first 5 bits can represent the computer room ID, and the last 5 bits can represent the machine ID. )
④, the fourth part, using 12 bits to represent the serial number, representing an increasing sequence, used to record different ids generated within the same millisecond
Splicing these 64 bits into a long type number is the realization of the snowflake algorithm.
        

2. The problem of loss of accuracy during use 

        When MyBatis-Plus implements addition, deletion, modification and query, id will be used as the primary key column by default, and when inserting data, the id will be generated based on the snowflake algorithm by default. However, if you do not pay attention during use, you will encounter the problem of loss of precision.

CREATE TABLE user
(
	id BIGINT(20) NOT NULL COMMENT '主键ID',
        #其他字段省略
);
@Data
public class User {
    private Long id;
//其他成员变量省略

        Use Long type to correspond to database ID data. The snowflake algorithm generates a string of numbers, and the Long type is the standard answer! Set a breakpoint on the backend. See the data response is given to the frontend in JSON,

{
id:1297873308628307970,
//其他属性省略
}

Finally, this piece of data is returned to the front end. After the front end receives it, it modifies the data, and the backend receives it back again.

The id received back by the backend becomes: 12978733086283000000, not 1297873308628307970

Solution:

①: The id field is changed from Long type to String type. (Not recommended, String ID query performance will drop )

②: The front-end uses the String type snowflake ID to maintain accuracy, and the back-end database continues to use the Long (BigINT) type   (yes!)

Back-end ID (Long) ==> Jackson (Long to String) ==> Front-end uses String type ID, and the front-end uses js string precision will not be lost
@Configuration
public class JacksonConfig {

  @Bean
  @Primary
  @ConditionalOnMissingBean(ObjectMapper.class)
  public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder)
  {
    ObjectMapper objectMapper = builder.createXmlMapper(false).build();

    // 全局配置序列化返回 JSON 处理
    SimpleModule simpleModule = new SimpleModule();
    //JSON Long ==> String
    simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
    objectMapper.registerModule(simpleModule);
    return objectMapper;
  }
}
③: Give up using the snowflake algorithm and use the unique self-incrementing id generated by MySQL. (Okay, it’s your choice)
        When using the @TableId(value = "id", type = IdType.AUTO) statement, it represents the use of the database's auto-increment strategy. Note that for this type, please ensure that the database has set the id auto-increment, otherwise it will be invalid.
        When the class name of the entity class type is inconsistent with the table name of the table to be operated, an error will be reported, and the annotation @TableName can help us solve this problem. My database table name is t_user, entity class name is User, just write @TableName("t_user") on the class name.
//设置实体类对应的表名
@TableName("t_user")
public class User {
    @TableId(value = "id",type = IdType.AUTO)
    private Long id;

When using the @TableId(value = "id") statement, if the primary key in the entity class and table is not id, but other fields, such as uid in the code, MyBatis-Plus will automatically recognize uid as the primary key column, otherwise it will Will report this error:

Guess you like

Origin blog.csdn.net/weixin_49171365/article/details/132569210