Maison > Java > javaDidacticiel > le corps du texte

Comment résoudre le problème de la perte de précision après la transmission de l'ID de clé primaire de l'algorithme SpringBoot Snowflake au frontal

PHPz
Libérer: 2023-05-11 12:34:18
avant
2794 Les gens l'ont consulté

Description du problème

Plage du backend Java Type long

  • -2^63~ 2 ^63, soit : -9223372036854775808~9223372036854775807, qui est le 19ème chiffre de 🎜🎜#.

  • Ce numéro peut être obtenu grâce aux méthodes : Long.MAX_VALUE, Long_MIN_VALUE.

La gamme de types de nombres dans le JS front-end

  • -2^ 53~2^53, soit : -9007199254740991~9007199254740991, qui est

    16 bits.

  • Ce numéro peut être obtenu grâce aux méthodes : Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER.

Conclusion

On peut voir que la largeur longue du backend Java est plus grande que celle de l'avant. L'algorithme du flocon de neige génère généralement des nombres d'une largeur de 18 ou 19 bits, des problèmes surviendront donc à ce moment-là.

Scénario du projet

1 Structure de la table

Le type de clé primaire est BIGINT, qui stocke l'ID généré. par l'algorithme du flocon de neige.

CREATE TABLE `user` (
  `id` BIGINT(32) NOT NULL COMMENT '用户id',
	...
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
Copier après la connexion

2.Entity

Utilisez le type Long pour correspondre au type BIGINT de l'ID de la base de données.

L'algorithme de flocon de neige de MybatisPlus est utilisé pour générer automatiquement un nombre pur à 19 chiffres comme identifiant de clé primaire. (Bien sûr, vous pouvez également générer manuellement l'identifiant à l'aide de l'algorithme du flocon de neige)

import lombok.Data;
 
@Data
public class User {
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
	
    //其他成员
}
Copier après la connexion

3 Répondez au front-end

Répondez. au front-end avec les données JSON normalement 🎜#
{
  "id": 1352166380631257089,
   ...
}
Copier après la connexion

Test#🎜 🎜 #

Visite : http://localhost:8080/user/find?id=1352213368413982722

Result

#🎜 🎜#

#🎜🎜 #problemrecurrence

Comme vous pouvez le voir ci-dessus, il n'y a pas de problème.

Pourquoi il n'y a pas de problème ?

Le front-end est transmis au back-end : SpingMVC convertira automatiquement l'ID de type String en type Long, et il n'y aura aucun problème. le front-end : il est au format JSON et n'a rien à voir avec JS Rien ne va mal

Comment résoudre le problème de la perte de précision après la transmission de lID de clé primaire de lalgorithme SpringBoot Snowflake au frontalQuand est-ce que quelque chose va mal ?

Une fois que le front-end a reçu le JSON, il le sérialise dans un objet JS puis effectue d'autres opérations. Il y aura des problèmes lors de la conversion de JSON en objets JS, comme suit :

Vous pouvez voir que l'ID d'origine est 1352213368413982722, et après sérialisation dans un JS objet, il devient 1352213368413982700

Le code est :

package com.knife.controller;
 
import com.knife.entity.UserVO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
@RequestMapping("user")
public class UserController {
 
    @GetMapping("find")
    public UserVO find(Long id) {
        UserVO userVO = new UserVO();
        userVO.setId(id);
        userVO.setUsername("Tony");
 
        return userVO;
    }
}
Copier après la connexion

SolutionIl y a deux solutions comme suit

# 🎜🎜 ## 🎜🎜#Modifiez le champ d'identification de la conception de la table de base de données du type Long au type String.

Comment résoudre le problème de la perte de précision après la transmission de lID de clé primaire de lalgorithme SpringBoot Snowflake au frontal

Le front-end utilise le type String pour enregistrer l'ID afin de maintenir la précision, et le back-end et la base de données continuent d'utiliser le type Long (BigINT) #🎜 🎜#

# 🎜🎜#L'option 1 utilise le type String comme ID de base de données et les performances des requêtes diminueront considérablement. L'option 2 devrait donc être adoptée. Cet article présente l'option 2.

Méthode 1 : Traitement global

Introduction

  • Custom ObjectMapper.

    Option 1 : ToStringSerializer (recommandé)
  • package com.knife.entity;
     
    import lombok.Data;
     
    @Data
    public class UserVO {
        private Long id;
     
        private String username;
    }
    Copier après la connexion
  • Test

    Visite : http://localhost:8080/user/find?id=1352213368413982722

Option 2 : Sérialiseur personnalisé (non recommandé)

Serializer

const json = '{"id": 1352213368413982722, "name": "Tony"}';
const obj = JSON.parse(json);
 
console.log(obj.id);
console.log(obj.name);
Copier après la connexion
#🎜 🎜#ObjectMapper configuration# 🎜🎜#
package com.knife.config;
 
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
 
@Configuration
public class JacksonConfig {
 
    @Bean
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
 
        // 全局配置序列化返回 JSON 处理
        SimpleModule simpleModule = new SimpleModule();
        // 将使用String来序列化Long类型
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }
}
Copier après la connexion
Test

Visite : http://localhost:8080/user/find?id=1352213368413982722

#🎜🎜 ##🎜 🎜#

Méthode 2 : Traitement local

Description

Comment résoudre le problème de la perte de précision après la transmission de lID de clé primaire de lalgorithme SpringBoot Snowflake au frontalAjouter : @JsonSerialize (using= ToStringSerializer .class).

Instance

package com.knife.config;
 
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
import com.fasterxml.jackson.databind.ser.std.NumberSerializer;
 
import java.io.IOException;
 
/**
 * 超出 JS 最大最小值 处理
 */
@JacksonStdImpl
public class BigNumberSerializer extends NumberSerializer {
 
	/**
	 * 根据 JS Number.MAX_SAFE_INTEGER 与 Number.MIN_SAFE_INTEGER 得来
	 */
	private static final long MAX_SAFE_INTEGER = 9007199254740991L;
	private static final long MIN_SAFE_INTEGER = -9007199254740991L;
 
	/**
	 * 提供实例
	 */
	public static final BigNumberSerializer instance = new BigNumberSerializer(Number.class);
 
	public BigNumberSerializer(Class<? extends Number> rawType) {
		super(rawType);
	}
 
	@Override
	public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException {
		// 超出范围 序列化位字符串
		if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) {
			super.serialize(value, gen, provider);
		} else {
			gen.writeString(value.toString());
		}
	}
}
Copier après la connexion

Test

Visite : http://localhost:8080/user/find?id =1352213368413982722

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:yisu.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal