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

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

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

    想问下大家怎么存储 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   ·   实用小工具   ·   2734 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 11:12 · PVG 19:12 · LAX 03:12 · JFK 06:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.