解决 MyBatis Plus 在 PostgreSQL 中 BigDecimal 精度丢失的问题

前言

在使用 MyBatis Plus 操作 PostgreSQL 数据库时,我们可能会遇到一个棘手的问题:BigDecimal类型的数据在存储或查询时精度丢失。这不仅会影响数据的准确性,还可能导致一些难以察觉的错误。本文将详细介绍这个问题的背景、排查过程以及最终的解决方案。

1.项目场景

在我的项目中,使用了 PostgreSQL 数据库,并且在表中定义了 NUMERIC 类型的字段来存储高精度数值。例如,我们有一个 data_cover 表,其中的 xy 字段被定义为 NUMERIC 类型,用于存储坐标值:

sql 复制代码
CREATE TABLE data_cover (
    id BIGINT NOT NULL,
    parking_id BIGINT,
    timestamp BIGINT,
    x NUMERIC,
    y NUMERIC,
    floor VARCHAR(255)
);

Java 实体类中,我们使用 BigDecimal 来映射这些字段:

java 复制代码
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;

@TableName("data_cover")
public class DataCover {
    @TableField("id")
    private Long id;

    @TableField("parking_id")
    private Long parkingId;

    @TableField("timestamp")
    private Long timestamp;

    @TableField("x")
    private BigDecimal x;

    @TableField("y")
    private BigDecimal y;

    @TableField("floor")
    private String floor;
}

然而,在插入或查询数据时,我们发现 xy 字段的精度丢失了,只保留了整数部分。这显然不符合我们的预期。

2.排查过程

  • 检查数据库字段定义 没问题
  • 检查 SQL 插入语句 没问题
  • 检查 MyBatis Plus 配置

在插入数据之前打印了 BigDecimal 的值,结果显示,BigDecimal的值在插入之前是正确的,但插入数据库后精度丢失。这表明问题可能出现在 MyBatis Plus 的类型处理逻辑中

3.原因分析

最终排查到,MyBatis Plus 默认的类型处理器可能没有正确处理 BigDecimal 的精度。默认情况下,MyBatis Plus 使用 JdbcType.NUMERIC 来处理 BigDecimal,但可能在某些场景下(如批量操作)导致精度丢失。

4.解决方案

创建了一个自定义的 BigDecimalTypeHandler 类,覆盖了 MyBatis 的默认行为:

java 复制代码
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

@MappedTypes(BigDecimal.class)
@MappedJdbcTypes(JdbcType.NUMERIC)
public class BigDecimalTypeHandler extends BaseTypeHandler<BigDecimal> {
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, BigDecimal parameter, JdbcType jdbcType) throws SQLException {
        ps.setBigDecimal(i, parameter); // 直接设置,避免精度丢失
    }

    @Override
    public BigDecimal getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return rs.getBigDecimal(columnName);
    }

    @Override
    public BigDecimal getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return rs.getBigDecimal(columnIndex);
    }

    @Override
    public BigDecimal getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return cs.getBigDecimal(columnIndex);
    }
}

然后,我们在 MyBatis Plus 的配置中注册了这个自定义类型处理器:

java 复制代码
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBatisConfig {
    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return configuration -> {
            configuration.getTypeHandlerRegistry().register(BigDecimal.class, BigDecimalTypeHandler.class);
        };
    }
}

通过自定义类型处理器,成功解决了 BigDecimal 精度丢失的问题。自定义类型处理器确保了在插入和查询时,BigDecimal 的精度不会被截断或修改。

5.总结

在使用 MyBatis Plus 操作 PostgreSQL 数据库时,BigDecimal 精度丢失的问题可能是由于默认的类型处理器没有正确处理高精度数值。通过自定义类型处理器,我们可以覆盖默认行为,确保精度不会丢失。

如果你在项目中遇到类似的问题,可以尝试以下步骤:

复制代码
1.检查数据库字段定义,确保字段类型和精度设置正确。
2.检查 SQL 插入语句,确保 BigDecimal 的值在插入之前是正确的。
3.检查 MyBatis Plus 的配置,确保没有对 BigDecimal 进行不必要的处理。
4.使用自定义类型处理器来确保精度不会丢失。

希望这篇文章能帮助你解决类似的问题。如果你有任何疑问或建议,欢迎在评论区留言!

相关推荐
HackTwoHub2 小时前
AI大模型网关存在SQL注入、附 POC 复现、影响版本LiteLLM 1.81.16~1.83.7(CVE-2026-42208)
数据库·人工智能·sql·网络安全·系统安全·网络攻击模型·安全架构
wuminyu2 小时前
专家视角看Java字节码加载与存储指令机制
java·linux·c语言·jvm·c++
l1t2 小时前
DeepSeek总结的DuckLake构建基于 SQL 原生表格式的下一代数据湖仓
数据库·sql
KmSH8umpK2 小时前
Redis分布式锁从原生手写到Redisson高阶落地,附线上死锁复盘优化方案进阶第八篇
数据库·redis·分布式
TDengine (老段)2 小时前
从施工监测到运营预警,桥科院用 TDengine 提升桥梁数据管理能力
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
callJJ3 小时前
Spring Data Redis 两种编程模型详解:同步 vs 响应式
java·spring boot·redis·python·spring
海兰3 小时前
【第27篇】Micrometer + Zipkin
人工智能·spring boot·alibaba·spring ai
S1998_1997111609•X3 小时前
论mysql国盾shell-sfa犯罪行为集团下的分项工程及反向注入原理尐深度纳米算法下的鐌檵鄐鉎行为
网络·数据库·网络协议·百度·开闭原则
wbs_scy4 小时前
Linux线程同步与互斥(三):线程同步深度解析之POSIX 信号量与环形队列生产者消费者模型,从原理到源码彻底吃透
java·开发语言
KmSH8umpK4 小时前
Redis分布式锁从原生手写到Redisson高阶落地,附线上死锁复盘优化方案进阶第七篇
数据库·redis·分布式