Fuhui

Deafult Decimal


版本 0.00

我说:version dependent 表示我们的思考时,应该依赖具体的版本。举个例子,你把2015年看到的一些redis机制拿到现在跟别人谈论,很容易闹出笑话。在3年的时间里,它可能已经做了无数的优化。所以,思考要与时俱进。

引言

在涉及到支付业务的时候,数据库里的钱怎么存:

  1. 存储单位是元。在业务处理的时候就会涉及到浮点数,很多商家喜欢将价钱定义为0.99而不是1元。这在使用过程中非常忌讳是否相等的比较。浮点数的比较经常喜欢用|floatA - floatB| > 0.00001来,很多第三方库也提供了比较方法。
  2. 存储单位时分。为了避免浮点类型比较时的不确定性,决定使用整形来替代。一般来说没有问题,可如果是要严格缺心眼打折,比如给一个售价4.99的打5折,那么最后就会存在5里的情况。一般都喜欢向上取整,应收用户2.495,实收用户2.50.

那么在MySQLColumn中该如何存储呢?

  1. 如果是分的话,肯定时当整形来存储的。但如果时浮点的,大家都会选择decimal,因为该类型不会丢失精度。
  2. 存储为字符串。浮点数保留指定位数的字符串。在Go中我也尝试过,fmt.Sprintf("%.2f", 3.091)还是靠谱的。

这篇文章当然不是来分析这两种存储方式的,也不是来分析该存储什么数据类型的。而仅仅时想阐述一个之前不了解的知识点(知识点太少,写点别的来凑)。

deault value

MySQL建表的过程中,一般都会指定DEFAULT VALUE。在执行INSERT时,如果不指定该字段,MySQL会默认使用该默认值来替代。下面是创建的一个decimal类型字段,在Go中使用xorm 来表示,可以看出,xorm使用字符串类型来接收decimal类型的值。

type table_test struct {
    PayPrice  string  `xorm:"not null default 0.00 comment('支付价钱') DECIMAL(10,2)"`
}

最后发现:在测试环境下,向数据库插入记录时,不指定PayPrice没有任何问题。但到了正式服数据表插入便失败了。报错信息如下:

{
    "Number": 1366,
    "Message": "Incorrect decimal value: '' for column 'pay_price' at row 1"
}

STRICT_TRANS_TABLES

查询sql_mode如下:

show variables like 'sql_mode'

下面的内容截取至:Strict SQL Mode:

Strict mode controls how MySQL handles invalid or missing values in data-change statements such as INSERT or UPDATE. A value can be invalid for several reasons. For example, it might have the wrong data type for the column, or it might be out of range.

最终定位:空字符串在该模式下转换decimal会失败,测试和线上数据库环境不一致