Rumah >Java >javaTutorial >Bagaimana untuk menyelesaikan masalah kehilangan ketepatan selepas ID kunci utama algoritma kepingan salji SpringBoot dihantar ke hujung hadapan

Bagaimana untuk menyelesaikan masalah kehilangan ketepatan selepas ID kunci utama algoritma kepingan salji SpringBoot dihantar ke hujung hadapan

PHPz
PHPzke hadapan
2023-05-11 12:34:182805semak imbas

Penerangan masalah

Julat hujung belakang Java Jenis panjang

  • -2^63~2^63, iaitu: -9223372036854775808~ 9223372036854775807, iaitu angka ke-19.

  • Nombor ini boleh diperolehi melalui kaedah: Long.MAX_VALUE, Long_MIN_VALUE.

Julat jenis angka JS bahagian hadapan

  • -2^53~2^53, yang ialah: -9007199254740991 ~9007199254740991, iaitu 16 bit.

  • Nombor ini boleh didapati melalui kaedah: Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER.

Kesimpulan

Ia boleh dilihat bahawa lebar Panjang bahagian belakang Java adalah lebih besar daripada bahagian hujung hadapan. Algoritma kepingan salji biasanya menjana nombor dengan lebar 18 atau 19 bit, jadi masalah akan berlaku pada masa ini.

Senario projek

1. Struktur jadual

Jenis kunci utama ialah BIGINT, yang menyimpan ID yang dijana oleh algoritma kepingan salji.

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

2.Entiti

Gunakan jenis Long untuk sepadan dengan jenis BIGINT ID pangkalan data.

Algoritma kepingan salji MybatisPlus digunakan di sini untuk menjana nombor tulen 19 digit secara automatik sebagai ID kunci utama. (Sudah tentu, anda juga boleh menjana ID secara manual menggunakan algoritma kepingan salji)

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

3 Balas ke hujung hadapan

Balas ke hujung hadapan dengan data JSON. biasanya

{
  "id": 1352166380631257089,
   ...
}

Penerangan Masalah

Instance

Pengawal

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

Entiti

package com.knife.entity;
 
import lombok.Data;
 
@Data
public class UserVO {
    private Long id;
 
    private String username;
}

Ujian

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

Hasil

Bagaimana untuk menyelesaikan masalah kehilangan ketepatan selepas ID kunci utama algoritma kepingan salji SpringBoot dihantar ke hujung hadapan

Penghasilan Semula Masalah

Sebagaimana anda boleh lihat dari atas tiada masalah.

Kenapa tiada masalah?

Halaman hadapan dihantar ke hujung belakang: SpingMVC akan menukar ID jenis String secara automatik kepada jenis Panjang, dan tidak akan ada masalah bahagian belakang bertindak balas kepada bahagian hadapan-. akhir: ia dalam format JSON, tiada kaitan dengan JS, dan tidak akan menyebabkan masalah

Bilakah sesuatu akan berlaku?

Selepas bahagian hadapan menerima JSON, ia mensirikannya menjadi objek JS dan kemudian melakukan operasi lain. Akan ada masalah apabila menukar JSON kepada objek JS, seperti berikut:

Bagaimana untuk menyelesaikan masalah kehilangan ketepatan selepas ID kunci utama algoritma kepingan salji SpringBoot dihantar ke hujung hadapan

Seperti yang anda lihat, id asal ialah 1352213368413982722, dan selepas disirikan ke dalam objek JS, ia menjadi 1352213368413982700

Kodnya ialah:

const json = '{"id": 1352213368413982722, "name": "Tony"}';
const obj = JSON.parse(json);
 
console.log(obj.id);
console.log(obj.name);

Penyelesaian

Terdapat dua penyelesaian seperti berikut

  • medan Tukar id reka bentuk jadual pangkalan data daripada jenis Long kepada jenis String.

  • Halaman hadapan menggunakan jenis String untuk menyimpan ID untuk mengekalkan ketepatan, dan bahagian belakang dan pangkalan data terus menggunakan jenis Long (BigINT)

Pilihan 1 menggunakan jenis Rentetan Apabila melakukan ID pangkalan data, prestasi pertanyaan akan menurun dengan ketara. Jadi pilihan 2 harus diterima pakai. Artikel ini memperkenalkan pilihan 2.

Kaedah 1: Pemprosesan global

Pengenalan

Pemeta Objek Tersuai.

Pilihan 1: ToStringSerializer (disyorkan)

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

Ujian

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

Bagaimana untuk menyelesaikan masalah kehilangan ketepatan selepas ID kunci utama algoritma kepingan salji SpringBoot dihantar ke hujung hadapanPilihan 2: Pengsiri tersuai (tidak disyorkan)

Pensiri

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

Konfigurasi ObjectMapper

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();
        // 将使用自定义序列化器来序列化Long类型
        simpleModule.addSerializer(Long.class, BigNumberSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, BigNumberSerializer.instance);
        objectMapper.registerModule(simpleModule);
        return objectMapper;
    }
}

Ujian

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

Bagaimana untuk menyelesaikan masalah kehilangan ketepatan selepas ID kunci utama algoritma kepingan salji SpringBoot dihantar ke hujung hadapan

Kaedah 2: Rawatan setempat

Arahan

Tambah: @JsonSerialize(using= ToStringSerializer.class) pada medan.

Instance

package com.knife.entity;
 
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
 
@Data
public class UserVO {
    @JsonSerialize(using= ToStringSerializer.class)
    private Long id;
 
    private String username;
}

Ujian

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

Atas ialah kandungan terperinci Bagaimana untuk menyelesaikan masalah kehilangan ketepatan selepas ID kunci utama algoritma kepingan salji SpringBoot dihantar ke hujung hadapan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam