Spring 数据 MongoDB BigDecimal 支持

Spring Data MongoDB BigDecimal support

伙计们,我对 Spring Data MongoDB 的 BigDecimal 值支持有疑问,有人可以帮我提供一些关于它的消息吗,如果有这种类型的支持,或者如果有人知道满足我需求的解决方法。就是这样:我正在做一个项目,我们使用 MongoDB 作为数据库,Spring 作为框架,我们想保存我们应该在数据库中获取货币值的字段作为BigDecimal,我读到 mongo 只接受双精度作为浮点数,但我认为这种类型不会有用。你们能给我一些说明吗?

Spring 数据 MongoDB 在写入时将 BigDecimal 值转换为 String 并在读取时返回。请查看参考手册的 data mapping and type conversion 部分。

可以通过 @Field(targetType=...) 修改默认转换,如下所示。

@Field(targetType = DECIMAL128)
private BigDecimal value;

您可以将 BigDecimal 的转换器更改为 Decimal128,这是 NumberDecimal 的 java 表示,因为 mongo 3.4:

@Bean
public MongoCustomConversions mongoCustomConversions() {
    return new MongoCustomConversions(Arrays.asList(

        new Converter<BigDecimal, Decimal128>() {

            @Override
            public Decimal128 convert(@NonNull BigDecimal source) {
                return new Decimal128(source);
            }
        },

        new Converter<Decimal128, BigDecimal>() {

            @Override
            public BigDecimal convert(@NonNull Decimal128 source) {
                return source.bigDecimalValue();
            }

        }


    ));

}

实际上自 Spring Data 2.0.7.RELEASE 以上更改为以下内容:

@Bean
public MongoCustomConversions mongoCustomConversions() {
    return new MongoCustomConversions(Arrays.asList(
        new BigDecimalDecimal128Converter(),
        new Decimal128BigDecimalConverter()
    ));

}

@WritingConverter
private static class BigDecimalDecimal128Converter implements Converter<BigDecimal, Decimal128> {

    @Override
    public Decimal128 convert(@NonNull BigDecimal source) {
        return new Decimal128(source);
    }
}

@ReadingConverter
private static class Decimal128BigDecimalConverter implements Converter<Decimal128, BigDecimal> {

    @Override
    public BigDecimal convert(@NonNull Decimal128 source) {
        return source.bigDecimalValue();
    }

}

我有一个极端情况,我有很多小数,Decimal128 的构造函数引发了以下异常:

Failed to convert from type [java.math.BigDecimal] to type [org.bson.types.Decimal128] for value '21.6000000000000000888178419700125232338905334472656250'; nested exception is java.lang.NumberFormatException: Conversion to Decimal128 would require inexact rounding of 21.6000000000000000888178419700125232338905334472656250

对此的解决方案是将输入向下舍入:

new Decimal128(source.round(MathContext.DECIMAL128))

如 Spring 数据 MongoDB - 参考文档 18.6. Custom Conversions - Overriding Default Mapping 中所述:

影响映射结果的最简单方法是通过 @Field 注释指定所需的本机 MongoDB 目标类型。这允许在域模型中使用非 MongoDB 类型,如 BigDecimal,同时以原生 org.bson.types.Decimal128 格式保留值。

public class Payment {

  @Field(targetType = FieldType.DECIMAL128) 
  BigDecimal value;

}

所需的目标类型明确定义为 Decimal128,即 NumberDecimal。否则 BigDecimal 值将变成 String:

{
  "value" : NumberDecimal(2.099)
}