新手问题 为什么要金额使用分为单位保存成整形在数据库中?

jasl · 2013年12月28日 · 最后由 jasl 回复于 2013年12月31日 · 9854 次阅读

找了很多资料都没有能解释清楚两者优缺点

记得19wu使用分为单位来保存金额,pq应该有decimal类型的,并且可以直接映射到Ruby的BigDecimal,可以说非常安全,为什么当初没采用呢? @doitian @saberma

PS:在mongodb中只能选择存分的形式,因为没有Decimal或者类似的数据类型,Mongoid会将BigDecimal转换成String保存,这将完全丧失查询能力,同时当前版本Mongoid的inc原子操作实现有bug,导致无法使用

共收到 26 条回复

我们是用的decimal

参考: http://ruby-china.org/topics/6982 http://ruby-china.org/topics/7376

用BigDecimal是安全的,但是,太麻烦了,还是用分直接一点,计算结算全用分,仅显示的时候格式化为元。

楼主问的是 BigDecimal 和用整数以分为单位的对比。

楼上两位都在说 float,话说用 float 保存金额的程序员怎么可能过试用期嘛,居然还有人点喜欢。

不知道是不是和Money用cents有关 它的解释是 Represents monetary values as integers, in cents. This avoids floating point rounding errors.

#2楼 @hisea 用decemal不会出现浮点数失精的问题,而且会ar会正确映射到BigDecemal,所以计算也是安全的

#3楼 @zj0713001 BigDecimal计算和普通数字类型 FIxnum还有Float都没啥差别吧

#3楼 @zj0713001 你可能会这么做

def price
    self.price_in_cents / 100.0
end

但用price去计算是一定会发生的,如果是Float,那么麻烦依然存在。所以,最终Ruby这边还是不得不去用BigDecimal

#9楼 @jasl 不用 / 100, 可以只用来显示的helper用 %100

好吧,我没仔细看原帖,我能想到的区别: 1, 内存跟储存的区别,两者是否占有同样大小空间? 2, 运算的效能, bigdecemal是比float慢的,integer比float要快的, 3, fixnum在ruby里面是inmutable,跟symbol一样,所有的5都是同一个对象,BigDecimal不是。 4,储存选择的灵活性跟通用性。

如果以上都不是考虑因素,那就无所谓了。

我们用的 postgres + decimal。Ruby 里直接用 BigDecimal。Ruby 2.1 开始可以用 decimal literal:0.1r

用 cents 保存的估计都不是金融系统(或是程序员懒惰),否则的话是没有办法处理一些金融方面的业务的,比如:http://en.wikipedia.org/wiki/Mill_%28currency%29

Mongo 没有 decimal?啊哈哈,估计也没太大关系,对数据精确度有要求的系统都不可能采用 Mongo 啊,LOL :trollface:

#11楼 @hisea http://stackoverflow.com/questions/18934774/what-are-the-downsides-to-storing-money-values-as-cents-minor-units 等等还有一堆其他的讨论,浏览器历史记录没了...但是没有一个明显的讨论能得出“最佳实践”

#12楼 @fredwu 我认为用cents是一种trick,另外这个cents是指代系统里金额的最小单位

不太理解为什么说存分是懒惰,毕竟会增加代码量,实际是复杂了...而且看了一些讨论之后,完全糊涂为什么不直接用decimal...

#12楼 @fredwu 或者说所有的系统都支持integer,那么用integer是最保守和最通用的解决方案

我们这的新人培训之一就是,遇到金额的数据库字段类型一定要用 BigDecimal,因为它有方法直接进行“银行家舍入法”,并且要是进行其他的舍入方法也能很方便的实现

PS:19wu 的里面我本来提了个金额用 BigDecimal 来储存的 issue,结果没被采用

#15楼 @jasl 在 java 里面的用 integer 存储金额的话,连13个9的那么一个金额都没法保存的,还是用 BigDecimal 的好

我查了下,可能是因为老版本的 MySQL(4.1及以下)的 decimal data type 是将数据保存为 string:

In MySQL versions up to and including 4.1, DECIMAL columns are represented as strings

http://dev.mysql.com/doc/refman/4.1/en/storage-requirements.html

#14楼 @jasl 即使是最小单位,当计算 currency conversion 的时候,还是会不够用的。;)

@jasl 没想这么多,两个方案选了一个

https://github.com/19wu/19wu/issues/474

@jasl @doitian 我把原贴讨论的翻出来了,两种都能满足要求。

#18楼 @fredwu #20楼 @doitian #21楼 @saberma

哦了 看来存分是一种trick

我公司的使用方式简单直接 所有商品最低价格都是元 所以不存在这么难过的讨论 我在其他地方使用分做最低单位 然后显示的时候用helper做的format...就是这样...

#23楼 @zj0713001 其实我们的定价也都是元... 支付宝的接口金额那块是decimal的字符串,不过财付通是分

为啥会出现分的方案让我很好奇,但是查了一些资料后没找到什么信息

#24楼 @jasl 其实源于很久以前没有decimal解决方案的时候 然后口口相传就成了这样的约定大于配置 其实怎么都行... 只要是确保金额安全 项目统一即可

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册