当前位置: 首页 > article >正文

MongoDB 字段中数据类型不一致序列化异常排查与处理

MongoDB 字段中数据类型不一致序列化异常排查与处理

背景如下,因为项目迁移愿意,一个使用Mongodb的业务拥有C#和Java两组Api。Java Api开发和测试都很顺利。上线一段时间后,客服反馈记录都不见了。查看数据库发现,时间字段拥有两种格式,其中一种是数组类型(如:[636693353404905287, 480]),另一种是日期类型(如:0001-01-01T00:00:00Z)

排查原因

首先看了原有C#代码的逻辑,使用的是DateTimeOffset类型存入的数据库。Java使用的是LocalDateTime类型。经过调用Api测试后,发现使用C#接口创建的数据,是数组格式。接下来就是在Java中对这个Document的序列化进行处理。

解决方案

首先看到[636693353404905287, 480],想到的就是时间戳,第二位应该保存的是时区。写了一个测试方法,将636693353404905287转为LocalDatetime,初步测试,将初始时间1901-01-01,时区偏移为480分钟。经过多种类型的测试,转化为了正确的时间(人工记忆创建记录的时间)。

知道了如何转化,就要在java解析时使用自定义的序列化器。

首先创建List转LocalDateTime的序列化器

import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;

/**
 *
 *
 * 包含如下格式脏数据,[636693353404905287, 480], 经测试是旧版c#接口导致的,并试验起始时间是"0001-01-01T00:00:00Z"
 * 并且此时间戳不需要进行时区转换
 */
@ReadingConverter
public class ArrayListToLocalDateTimeConverter implements Converter<List<Object>, LocalDateTime> {

    @Override
    public LocalDateTime convert(List<Object> source) {
        if (source.size() >= 2 && source.get(0) instanceof Long) {
            long timestamp = (Long) source.get(0);
            // 假设起始时间是"1601-01-01T00:00:00Z",请根据需要进行调整
            Instant startInstant = Instant.parse("0001-01-01T00:00:00Z");
            // 注意:原始时间戳可能需要根据实际情况调整计算方式
            Instant actualInstant = startInstant.plusMillis(timestamp / 10_000);
            return LocalDateTime.ofInstant(actualInstant, ZoneOffset.UTC);
        }
        throw new IllegalArgumentException("Invalid source for conversion: " + source);
    }
}

然后在MongoDB的配置类中注册

import com.mongodb.MongoClientURI;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;

import java.util.Arrays;

@Configuration
public class MongoConfig {


    @Value("${spring.data.mongodb.uri}")
    private String uri;


    @Bean(name = "mongoTemplate")
    @Primary
    public MongoTemplate mongoTemplate() {
        MongoTemplate template = new MongoTemplate(mongoDbFactory());
        customizeMongoTemplate(template);
        return template;
    }

    @Bean
    @Primary
    public MongoDbFactory mongoDbFactory() {
        return new SimpleMongoDbFactory(new MongoClientURI(uri));
    }

    /**
     * 为了解决mongodb中的时间戳转换问题
     */
    @Bean
    public MongoCustomConversions mongoCustomConversions() {
        return new MongoCustomConversions(Arrays.asList(
                new ArrayListToLocalDateTimeConverter()
        ));
    }

    private void customizeMongoTemplate(MongoTemplate template) throws Exception {
        MappingMongoConverter converter = (MappingMongoConverter) template.getConverter();
        converter.setCustomConversions(mongoCustomConversions());
        converter.afterPropertiesSet();
    }

}

uri:其中uri时从配置文件中读取的,mongo 的数据库连接。
mongoTemplate:注入MongoTemplate,用于操作数据库。
mongoCustomConversions:注入自定义的转换器,用于将数据库中的数据转换为Java中的数据。
customizeMongoTemplate:将自定义的转换器注入到MongoTemplate中。

这种是单数据源配置,如果要有多数据源,将MongoTemplate和MongoDbFactory复制,的注入名称修改为不同的名称即可。

总结

经过配置,如果类型是数组,则会触发进行解析。该字段正常的数据可以直接映射。

后续会将C#的流量转发到Java接口,然后将C#接口下线。


http://www.kler.cn/a/229978.html

相关文章:

  • 英语知识网站开发:Spring Boot框架应用
  • 数据绑定与状态管理
  • 【汽车制动】汽车制动相关控制系统
  • 爬虫开发(5)如何写一个CSDN热门榜爬虫小程序
  • SpringCloud入门实战-Nacos简介、安装、运行详解
  • 【vue3实现微信小程序】从轮播图到公告栏的前端开发之旅
  • 20240206在WIN10下下载安装RX580的驱动程序
  • 新概念英语第二册(56)
  • leetcode(双指针)283.移动零(C++)DAY3
  • C++多线程:this_thread 命名空间
  • 瑞_23种设计模式_原型模式
  • 京东广告算法架构体系建设--大规模稀疏场景高性能训练方案演变
  • UE5 虚幻游戏报错常用解决方法(幻兽帕鲁UE5报错)
  • 关于ZYZ旋转和XYZ旋转
  • 介绍 MSTest Runner – CLI、Visual Studio 等
  • 前端实现搜索框筛选
  • 【DDD】学习笔记-数据模型与对象模型
  • 微信小程序for循环嵌套
  • 使用STM32 HAL库配置和控制外设接口
  • 【SQL高频基础】1141.查询近30天活跃用户数
  • 基于SSM的实习管理系统(有报告)。Javaee项目。ssm项目。
  • vue2 自定义指令 v-highlight 文本高亮显示分享
  • 常用加密算法
  • 爬虫(三)
  • ELFK日志采 - QuickStart
  • 机器人抓取 [ 题目/摘要 ] 更新中..