Java enum 数据库存储问题(大家都是存字符串还是数值) - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
sdbybyd
V2EX    Java

Java enum 数据库存储问题(大家都是存字符串还是数值)

  •  1
     
  •   sdbybyd 2020-09-25 18:11:12 +08:00 6035 次点击
    这是一个创建于 1843 天前的主题,其中的信息可能已经有所发展或是发生改变。

    想问下大家怎么存储 enum 的,是字符串存储还是数值存储? 比如:

    Gender { MALE, FEMALE }

    41 条回复    2020-09-30 17:30:21 +08:00
    lower
        1
    lower  
       2020-09-25 18:20:04 +08:00
    byte
    lower
        2
    lower  
       2020-09-25 18:20:49 +08:00
    @lower 说错了,bit
    sdbybyd
        4
    sdbybyd  
    OP
       2020-09-25 18:30:18 +08:00
    @lower 你 @ 了自己,bit 指的是数值瞄?
    GM
        5
    GM  
       2020-09-25 18:44:08 +08:00
    以下为我经常使用的做法,定义一个 enum,enum 里定义好 Json 、Jpa 等转换规则。

    仅供参考:

    ```
    @Getter
    @AllArgsConstructor
    public enum State {
    UNKNOWN("未知"),
    ACTIVE("正常"),
    INACTIVE("封禁"),
    ;

    private final String desc;

    @JsonCreator
    public static State fromStr(String strValue) {
    return Arrays.stream(State.values()).filter(value -> value.value().equals(strValue)).findFirst().orElse(UNKNOWN);
    }

    @JsonValue
    public String value() {
    return this.name();
    }

    @Converter(autoApply = true)
    public static class DatabaseColumnConverter implements AttributeConverter<State, String> {
    public String convertToDatabaseColumn(State state) {
    return state != null ? state.name() : UNKNOWN.name();
    }

    public State convertToEntityAttribute(String name) {
    return fromStr(name);
    }
    }
    }

    ```
    xiangyuecn
        6
    xiangyuecn  
       2020-09-25 18:49:38 +08:00   1
    enum 能做的 class 都能做。

    enum 不能做的 class 都能做。

    enum 各种蹩脚规范代码编写约束,本质上还是一个 class,但开头不能放别的东西,气不气人?

    有什么理由用 enum ?没有!
    chana71
        7
    chana71  
       2020-09-25 19:10:14 +08:00
    @huijiewei 你这个是撸了个枚举类吗
    GM
        8
    GM  
       2020-09-25 19:24:21 +08:00
    @xiangyuecn enum 能 switch case,class 能吗?
    GM
        9
    GM  
       2020-09-25 19:25:56 +08:00
    @xiangyuecn
    enum 可以直接 if(user.state == State.INACTIVE) { ... },class 能吗?
    huijiewei
        10
    huijiewei  
       2020-09-25 19:33:08 +08:00
    @GM 我贴的代码可以啊

    user.state == UserState.INACTIVE.getValue()

    即可
    yiyi11
        11
    yiyi11  
       2020-09-25 19:33:30 +08:00 via Android
    啊?不是都存码表的码吗?数据库有码表,1-xxx,2-yyy,其他表存的是码“1”或“2”。枚举定义成 xxx(“1”,“xxx”)。不管哪里的数据都是以码为准,码对应的值是描述解释(或做显示用),枚举仅仅是为了消除代码中的魔法值,跟码表一一对应的。
    GM
        12
    GM  
       2020-09-25 19:39:42 +08:00
    @huijiewei
    enum 存字符串的好处主要是一目了然,不用看着表里的 1 、2 、3 、4 去猜,比较方便。不然就得去代码里找对应文档或注释(碰到那些缺乏注释的项目,会很恶心)。

    PS:多一个 .getValue() 感觉还是很不爽的,不如直接 user.state == UserState.INACTIVE
    baobao1270
        13
    baobao1270  
       2020-09-25 19:42:20 +08:00
    不是 Java,是 .NET ,存 Enum 。数据库里写注释,再说,有 EFCore 基本很少要动数据库
    GM
        14
    GM  
       2020-09-25 19:43:32 +08:00
    @huijiewei 去看了一下你的代码,你这做法不是不行,但是定义、使用太麻烦了,不如 enum 好用。

    我个人是很喜欢 java 的 enum 设计的,用对路了会感觉很好用。事实上,我写 C#项目的时候,还专门弄了一个 Enum 类来模拟 java 的 enum 。
    wdmx007
        15
    wdmx007  
       2020-09-25 21:18:11 +08:00 via Android
    不推荐存数字,也就是 ordinal 。因为这是和枚举各项顺序有关的,有脑抽的调整了顺序就炸了
    lululau
        16
    lululau  
       2020-09-25 21:56:41 +08:00 via iPhone
    存数值也可以不存 ordinal value,可以自定义使用数值型属性的值的,但我认为应该存字符串,就一个原因,只看 db 存的值我就知道当前这条记录是什么状态、类型了
    MarioLuo
        17
    MarioLuo  
       2020-09-25 22:14:36 +08:00 via Android
    直接用字符串,许多框架库(spring, mybatis,...)对枚举默认值处理方式就是字符串
    EminemW
        18
    EminemW  
       2020-09-25 22:40:06 +08:00
    我的 enum 是用来看的。。不存数据库,因为我不知道怎么比较合理利用
    zsdroid
        19
    zsdroid  
       2020-09-25 23:39:22 +08:00
    @huijiewei 1 为什么不推荐用 ENUM ? 2.你的比 java 自带的好在哪?
    sdbybyd
        20
    sdbybyd  
    OP
       2020-09-26 01:18:37 +08:00
    @GM 这也是我现在在用的方法,就是列举一些值,写个 mybatis 的 converter 转换存储,但是我看了 fb 还有 阿里的很多接口,对外暴露用的字符串,这样 java 的 enum 就简单了,直接命名就行,mybatis 有默认 converter 插入,可能 fb 阿里都有自动化工具转值存储 db
    sdbybyd
        21
    sdbybyd  
    OP
       2020-09-26 01:19:18 +08:00
    @huijiewei 你这个做法应该不行,还不如手撸 converter
    sdbybyd
        22
    sdbybyd  
    OP
       2020-09-26 01:23:02 +08:00
    @xiangyuecn enum 的好处很多,比如类型检查(不是 Integer 数值类型检查),如果你可以直接这么写

    ```java
    public enum Gender {
    MALE,
    FEMALE;
    }
    ```

    而且有自动化工具帮你存储数据库时转换为数值存储,如 1,2,提取时自动转换,这种状态维护起来就简单多了

    我想要的就是这种自动化工具(不用硬编码数值,看了一些 api,fb 和阿里就有这么搞)。
    sdbybyd
        23
    sdbybyd  
    OP
       2020-09-26 01:24:03 +08:00
    @yiyi11 你说的数据库码表指的是?特定数据库类型?还是在 java 上编码的数值映射
    sdbybyd
        24
    sdbybyd  
    OP
       2020-09-26 01:38:43 +08:00
    @MarioLuo 直接用字符串的话,作为索引的时候是不是太浪费了,有没优化方法
    dswyzx
        25
    dswyzx  
       2020-09-26 02:06:32 +08:00 via iPhone
    c#里,enum 是值类型,class 可是引用类型。根本性不同。enum 映射 db 当然是数值类型了。二楼说 bit 的,刚好性别男女是够用了,以后扩展人妖或者啥啥的时候你怎么存
    MarioLuo
        26
    MarioLuo  
       2020-09-26 03:44:14 +08:00 via Android
    @sdbybyd 数据量不高的情况下索性性能差异不大, 而且大多数情况下枚举字段并不适合作为索引列
    MarioLuo
        27
    MarioLuo  
       2020-09-26 04:13:27 +08:00 via Android
    @sdbybyd 枚举增加数值属性, 实现 IntCode 接口,然后为相关的库针对这个接口通用的转换器(mybatis, jpa, spring mvc,...)

    enum Gender implement IntCode{
    MALE(1),
    FEMALE(2);
    private Integer code;
    public Integer getCode(){ return code; }
    }

    interface IntCode{
    Integer getCode()
    }
    binux
        28
    binux  
       2020-09-26 05:05:41 +08:00 via Android
    数据库也用枚举类型不就完了
    huijiewei
        29
    huijiewei  
       2020-09-26 06:40:53 +08:00
    @zsdroid 不用 ENUM 是因为如果数据库里面有 ENUM 不存在的值。API 输出会很麻烦
    huijiewei
        30
    huijiewei  
       2020-09-26 06:46:00 +08:00
    @binux 因为大部分人用 mysql,mysql ENUM 类型坑比较多,现在都不推荐使用 ENUM
    ez728s
        32
    ez728s  
       2020-09-26 09:12:24 +08:00 via Android
    数据库里面应该存储有明确意义的字符串值而不是不知所谓的 1234 数值
    xiangyuecn
        33
    xiangyuecn  
       2020-09-26 10:29:08 +08:00
    @sdbybyd #22 解决硬编码数值(应该叫魔术数值)问题,应当首选常量,而不是 enum,比如 Android 里面的 startActivityForResult 中的 requestCode 这个反人类数值参数,用 enum 当然可以,但不会去用的,基本定义成常量的
    zeroday
        34
    zeroday  
       2020-09-26 10:58:04 +08:00
    直接用 mysql 里的 ENUM 类型. 因为是非常快和紧凑的。在实际上,其保存的是 TINYINT,但其外表上显示为字符串。
    如果有一个字段,比如“性别”,“国家”,“民族”,“状态”或“部门”,你知道这些字段的取值是有限而且固定的,那么,你应该使用 ENUM 。
    yiyi11
        35
    yiyi11  
       2020-09-26 11:23:48 +08:00 via Android
    @sdbybyd 数值映射
    tailf
        36
    tailf  
       2020-09-26 12:00:14 +08:00
    数据库不要用 enum,用 tinyint
    skypyb
        37
    skypyb  
       2020-09-26 14:16:29 +08:00
    用 postgres 就没这破事了
    notejava
        38
    notejava  
       2020-09-26 16:40:00 +08:00
    字符串,可读性好
    tairan2006
        39
    tairan2006  
       2020-09-26 17:22:20 +08:00
    tinyint/smallint
    sdbybyd
        40
    sdbybyd  
    OP
       2020-09-30 12:03:59 +08:00
    @MarioLuo 我们目前就是这么做的,但是还是需要定义数值,数值定义不好规范,想要数据库插入就是字符串(实际存储用的数值)这部分对开发者隐藏的同时规避 数据库 enum 类型的缺陷
    MarioLuo
        41
    MarioLuo  
       2020-09-30 17:30:21 +08:00 via Android
    @sdbybyd 那问题就是数字从哪儿来,依赖枚举 ordernal 是不应该的
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     952 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 22:59 PVG 06:59 LAX 15:59 JFK 18:59
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86