V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wisetc
V2EX  ›  数据库

金额的存储用 long 可以吗

  •  
  •   wisetc · 2019-05-30 14:48:17 +08:00 · 8837 次点击
    这是一个创建于 2009 天前的主题,其中的信息可能已经有所发展或是发生改变。
    想将金额的数值乘以 1000 然后再存库,方便数据的存储。让前端提交给后端的数据都先乘以 1000,然后后端返回给前端的金额数据是放大了 1000 倍的,显示的时候再让前端处理,除以 1000,后台不用对金额做任何处理,哈哈哈。我真是越来越佩服我自己。
    各位后端大佬,怎么看。
    81 条回复    2019-05-31 14:17:20 +08:00
    adzchao
        1
    adzchao  
       2019-05-30 14:51:35 +08:00   ❤️ 1
    完全可以 看精确到多少位 后端就是这么搞的
    surfire91
        2
    surfire91  
       2019-05-30 14:51:48 +08:00
    精度够的话当然可以。
    ezksdo
        3
    ezksdo  
       2019-05-30 14:53:33 +08:00
    用整数,存的时候乘 100
    mawenjie
        4
    mawenjie  
       2019-05-30 15:04:49 +08:00
    这不是常识吗,你敢用浮点数搞?
    tabris17
        5
    tabris17  
       2019-05-30 15:08:53 +08:00
    既然有 decimal 为什么不用?
    wisetc
        6
    wisetc  
    OP
       2019-05-30 15:11:05 +08:00
    各位大佬,其实我是前端,乘以 1000,然后再除以 1000,好烦哦,再前端搞来搞去太容易出错了,我就是吐个槽,看看有没有更高级的做法,比如在数据库前面加个网,好比过了就是天上一天地下一年
    neuthself
        7
    neuthself  
       2019-05-30 15:11:38 +08:00
    《高性能 MySQL 》也有讲到类似的方式,可以有但感觉没必要,直接用 decimal 吧
    jifengg
        8
    jifengg  
       2019-05-30 15:30:59 +08:00
    金额,我一般都是统一单位为“分”,因为金额一般要涉及到加减的操作,用整数能保证精度。
    RubyJack
        9
    RubyJack  
       2019-05-30 15:38:24 +08:00
    decimal
    TheCure
        10
    TheCure  
       2019-05-30 16:20:13 +08:00
    这不是大学就学的么..
    keepeye
        11
    keepeye  
       2019-05-30 16:23:18 +08:00
    有些情况下要对金额做除法,就会出现小数了,如果不精确的话可能会导致金额出现偏差 1 分
    zgl263885
        12
    zgl263885  
       2019-05-30 16:26:12 +08:00 via iPhone
    我时间戳都用的 long,前端拿到后自己再处理下。可读性和性能能好的一匹。
    wolfie
        13
    wolfie  
       2019-05-30 16:35:28 +08:00
    别像摩拜用 int 就行
    txwd
        14
    txwd  
       2019-05-30 16:38:49 +08:00
    见过用 4 位小数的,天坑
    hailiang88
        15
    hailiang88  
       2019-05-30 16:39:05 +08:00 via iPhone
    前端操作金额会有精度问题,需要单独处理
    nszm
        16
    nszm  
       2019-05-30 16:44:10 +08:00   ❤️ 1
    乘除这种给后端操作,前端这个搞不是搞事情吗
    gogogogogo
        17
    gogogogogo  
       2019-05-30 16:49:45 +08:00
    iOS 端会有精读问题
    rockyou12
        18
    rockyou12  
       2019-05-30 16:57:32 +08:00   ❤️ 3
    后端这样存其实算是常规操作。前端好像有个 decimal.js (好像叫这个)的库可以做精确的数字运算,我觉得 lz 可能需要的是这个
    swulling
        19
    swulling  
       2019-05-30 16:58:00 +08:00 via iPhone
    钱一定要用整数存…存成分就行了
    9151
        20
    9151  
       2019-05-30 17:04:09 +08:00   ❤️ 5
    楼主在搞什么山寨币?
    shihty5
        21
    shihty5  
       2019-05-30 17:10:06 +08:00   ❤️ 1
    BigDecimal
    whypool
        22
    whypool  
       2019-05-30 17:12:00 +08:00
    用整数,存分或者厘
    Caballarii
        23
    Caballarii  
       2019-05-30 17:12:10 +08:00
    上面说存成分的都是没做过利率计算的吧
    indingpig
        24
    indingpig  
       2019-05-30 17:27:56 +08:00   ❤️ 1
    计算的话还是交给后台计算吧,前端计算精度有可能出问题的。比如长度超过 17 位的数,精度就开始丢失,前端最大和最小的安全整数是正负 2 的 53 次方-1
    tonghuashuai
        25
    tonghuashuai  
       2019-05-30 19:08:06 +08:00
    Decimal
    julyclyde
        26
    julyclyde  
       2019-05-30 19:10:42 +08:00   ❤️ 1
    老老实实用 currency 类型,别找事
    qiyuey
        27
    qiyuey  
       2019-05-30 19:15:06 +08:00 via Android
    一般是用分
    shm7
        28
    shm7  
       2019-05-30 19:17:22 +08:00 via iPhone
    一看就不知道有个 format 叫 bank format (小数点后两位),后面的就可以拿来 tanwu 了
    SingeeKing
        29
    SingeeKing  
       2019-05-30 19:27:07 +08:00
    为什么是 1000 而不是 100 …… 微信支付就是以分为单位的
    RangerWolf
        30
    RangerWolf  
       2019-05-30 19:27:51 +08:00
    谷歌广告的数据就是这么干的~ 你说可以么?

    但是直接用 decimal 个人觉得也不错
    ETiV
        31
    ETiV  
       2019-05-30 19:29:20 +08:00 via iPhone
    LZ 好厉害,我都要佩服 LZ
    passerbytiny
        32
    passerbytiny  
       2019-05-30 19:36:22 +08:00   ❤️ 2
    @SingeeKing #27 以前虽然现金只到分,但算账的时候要算到厘。严格意义上说,微信支付是有问题的,因为现在现金是只到角的,分、厘都只能用于计算,不能用于最后的支付。
    lithiumii
        33
    lithiumii  
       2019-05-30 19:54:53 +08:00
    反正我司用的 float,偶尔出现一些奇幻情况,我都惊了
    JerryCha
        34
    JerryCha  
       2019-05-30 20:48:48 +08:00
    我用 String (逃
    troywinter
        35
    troywinter  
       2019-05-30 22:37:39 +08:00
    #3 是正解,用整型存储最后处理时除以 100 是常识操作,不应该用其它方式,至于出错的问题 ddd 完全可以解决。
    IceBay
        36
    IceBay  
       2019-05-30 22:40:20 +08:00
    就用 decimal,计算用高精度函数。
    ccming
        37
    ccming  
       2019-05-30 22:42:40 +08:00 via iPhone
    @troywinter 汇率怎么处理
    dosmlp
        38
    dosmlp  
       2019-05-30 23:32:55 +08:00
    @lithiumii 用 float 也是牛鼻,float 各种运算精度更差
    limuyan44
        39
    limuyan44  
       2019-05-30 23:44:49 +08:00 via Android
    真不怕无中丢钱,无中生钱?
    lithiumii
        40
    lithiumii  
       2019-05-30 23:47:13 +08:00 via Android
    @dosmlp 是啊,我看到都吐血了
    conn4575
        41
    conn4575  
       2019-05-31 00:05:32 +08:00 via Android
    说存分的肯定没真正处理过金额问题,金额不是只有加减好吗,还有除法,用整数肯定存在精度问题,老老实实用 decemal,而且最好要 12 位以上小数
    ericgui
        42
    ericgui  
       2019-05-31 00:18:45 +08:00
    应该是按照货币的最小单位
    比如,美元,最小是美分,就应该乘以 100
    人民币,最小是分,乘以 100

    日元和韩元,似乎没有分,就是正整数,1 就是 1 元
    h123123h
        43
    h123123h  
       2019-05-31 01:03:01 +08:00
    7/3 这种小数怎么办?特别是参与多次运算,精度问题误差会越来越大,看来楼上的都没做过金额处理啊
    h123123h
        44
    h123123h  
       2019-05-31 01:04:20 +08:00
    老老实实用 Bigdecimal
    MonoLogueChi
        45
    MonoLogueChi  
       2019-05-31 02:17:18 +08:00 via Android
    @keepeye 所以要多保存一位,控制除法的精确度
    tsui
        46
    tsui  
       2019-05-31 03:38:53 +08:00
    @h123123h 正解。。必须只能 BigDecimal,怎么可能用 Decimal
    ytmsdy
        47
    ytmsdy  
       2019-05-31 08:06:08 +08:00 via iPhone
    用 long 如果四舍五入没问题的话就用吧!要不然后期对账对死你!
    gavindexu
        48
    gavindexu  
       2019-05-31 08:07:05 +08:00 via iPhone
    涉及除法的话,
    能不能加俩字段去保留分子分母?
    一定要存储结果么……🤔
    GTim
        49
    GTim  
       2019-05-31 08:49:39 +08:00
    用!而且一定要要,所有计算都直接用,只有在显示用户看的时候除 100。前端也一样
    toxicant
        50
    toxicant  
       2019-05-31 09:05:08 +08:00 via Android
    金额还能让前端处理的吗...
    Ciallo
        51
    Ciallo  
       2019-05-31 09:09:54 +08:00
    BigDecimal 吧
    22too
        52
    22too  
       2019-05-31 09:10:03 +08:00   ❤️ 3
    decimal 这个才是正解
    1. 万一那天有个人写了一个 bug, 会不会出现金额多了 1000 倍. 无端制造风险
    2. 不要理想的以为,金钱就涉及到加减法,乘除法也是经常出现的
    3. 很多时候,分并不是最小单位,比如 某借呗 按照日万五收取利息, 这样会产生比分更小单位.
    yidinghe
        53
    yidinghe  
       2019-05-31 09:19:31 +08:00
    我们是拿分做单位。
    liuxey
        54
    liuxey  
       2019-05-31 09:21:13 +08:00
    银行一般的精度是:Decimal(18,6) -> 999999999999.999999
    AlloVince
        55
    AlloVince  
       2019-05-31 09:28:31 +08:00
    既然大家说钱都是默认以元为单位,就不要做违反直觉的设计
    zealinux
        56
    zealinux  
       2019-05-31 09:31:26 +08:00
    存:分子和分母

    298.6734
    分子:2986734
    分母:10000
    chenuu
        57
    chenuu  
       2019-05-31 09:38:36 +08:00
    存货币的最小单位
    justicelove
        58
    justicelove  
       2019-05-31 09:43:43 +08:00
    不单单要看存储的需要, 还要看计算的需要
    RRRoger
        59
    RRRoger  
       2019-05-31 09:46:16 +08:00
    有的国家是 0.001 怎么办 我们支持多货币的
    karllynn
        60
    karllynn  
       2019-05-31 09:59:28 +08:00
    用整形没有问题的,用 decimal 也可以,不过 js 的浮点数精度丢失问题好像很严重
    brust
        61
    brust  
       2019-05-31 10:11:31 +08:00
    @txwd
    这边有 5 位的
    还是 varchar
    luozic
        62
    luozic  
       2019-05-31 10:19:36 +08:00
    小數直接切了?
    wisetc
        63
    wisetc  
    OP
       2019-05-31 10:19:57 +08:00
    因为有时候金额既有用户输入又有后台代入,并不十分确定金额的来向是用户输入,用户输入的情形用来显示显然不需要做放大,然后混合系统来的数据就可能会出现问题,而且金额放大 1000 倍直观上感受并不能判断是放大后的结果(例如 1000,看不出是 1 元还是 1000 元),出现不确定性。于是,前端提倡,在前端运行中的过程量都是直接的真实数据,不希望做任何的特殊处理,对请求的后台接口封装做请求参数和返回数据的处理,但是有时候涉及到遍历,和特殊处理,这又是常见的一般性问题了,金额的字段名也不固定而且有时不必需,这显然却是一种运算力的浪费。
    tailf
        64
    tailf  
       2019-05-31 10:23:44 +08:00
    用 decimal,没有对账风险
    allanzhuo
        65
    allanzhuo  
       2019-05-31 10:26:42 +08:00
    我司有个十几年的所谓架构师也是这样设计的,最后他滚蛋了,哈哈哈
    wlfeng
        66
    wlfeng  
       2019-05-31 10:34:00 +08:00
    和钱有关的数据老老实实用 decimal,不要搞事情,不然出问题了你哭都来不及
    wupher
        67
    wupher  
       2019-05-31 10:45:41 +08:00
    可以

    如果计算量很多很大,使用 long 会比使用 Big Decimal 效率高很多。更别提 Big Decimal 的进位策略。

    但是,使用 long 也要评估是否会碰到溢出。尤其是大规模统计的情况下。
    CantSee
        68
    CantSee  
       2019-05-31 10:56:19 +08:00
    decimal 啊,这玩意跟数据库同步,多方便
    jzmws
        69
    jzmws  
       2019-05-31 11:07:14 +08:00
    我第一反应为什么不用 decimal 货币型 ,最不济的用 bigint 按分来存
    SayNight
        70
    SayNight  
       2019-05-31 11:08:26 +08:00   ❤️ 1
    如果业务场景金额只有加减,且判断以后绝对不会有复杂运算,因为是扩大倍数存储,要考虑 long 型溢出问题。

    建议 BigDecimal,前面有 V 友提到银行用的是这个。曾在支付公司待过几年,每天流水十来亿,只允许使用:BigDecimal。不然很容易搞出事。
    sivacohan
        71
    sivacohan  
       2019-05-31 11:08:34 +08:00
    看你常见,如果是简单的购买行为,那你的方法是可以的。
    如果是金融系统,一般做法是 Decimal 保留 4 到 6 位小数,然后定期核查,检查因为精度问题造成的损失。
    最常见的常见就是 100 块钱三个人平分,最后总会有一个人多分到一分钱。
    jzmws
        72
    jzmws  
       2019-05-31 11:08:53 +08:00
    @keepeye 最好做个四舍六入的 要不然到最后帐不平 .
    yalin
        73
    yalin  
       2019-05-31 11:11:52 +08:00
    听说平安一钱包大佬用这个库: https://github.com/JodaOrg/joda-money
    msg7086
        74
    msg7086  
       2019-05-31 12:00:20 +08:00
    如果你是无关紧要的金融服务,比如开 VPS 收个钱什么的,那存个千分之一元也就算了。
    如果是以金融为核心的服务,当然直接开大数运算咯,Decimal 或者金融专用小数格式直接用就是了。
    fairyto2
        75
    fairyto2  
       2019-05-31 12:20:00 +08:00
    @22too 而且也只能从 String 初始化
    thet
        76
    thet  
       2019-05-31 12:58:39 +08:00 via Android
    我是直接用的 decimal
    lzj307077687
        77
    lzj307077687  
       2019-05-31 13:41:20 +08:00
    反正我认为我的项目 decimal 是够用的
    li24361
        78
    li24361  
       2019-05-31 13:58:16 +08:00
    @9151 还有可能 p2p
    ZiLong
        79
    ZiLong  
       2019-05-31 14:04:57 +08:00
    Bigdecimal 挺好,就是那个效率是真真的慢
    VANHOR
        80
    VANHOR  
       2019-05-31 14:07:01 +08:00
    用整型,存分就可以。
    shuqin2333
        81
    shuqin2333  
       2019-05-31 14:17:20 +08:00
    我们公司使用的 long,mysql 数据类型用的 bigint。前台存取的时候自行*/10000
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1795 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 16:34 · PVG 00:34 · LAX 08:34 · JFK 11:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.