如何较好地管理数据库中的各种字段状态?

抽象一个业务:

        我们有一张任务表(ts_mission),任务的完成状态(mission_status)有两种类型——

        init(未处理)

        finished(已完成)

我们需要在数据库中存储状态的类型,还需要读取状态,以及存储状态。

1、常规处理字段状态的方式

作为一个简单粗暴的程序员,甭给老夫说什么底层、架构,老夫敲代码就是一梭子,Ctrl + C,Ctrl + V,拿起就是干。

额,不好意思,走远了~

我们最简单快捷的做法就是直接在数据库表中创建"mission_status"这个状态,然后根据任务是否完成存储"init"或者"finished",来标志他是"未处理",还是"已完成"。

当一个系统比较小,业务量不复杂的时候,这么做确实可以加快效率,能快速完成我们需要的功能。

可是当数据量上升时,我们就会很难去维护管理这些个状态,一个任务状态还轻松,当有成百上千的状态躺在数据库表中,就非常不便于管理。

为了知晓这个"init"是什么意思,就得翻看注视或者代码去看这个状态到底是什么意思。

ps:当然,有直接将字段状态存储为中文的做法,但是业界不这么做,毕竟存储英文不会因为编码造成读取错误。

然后,我们在做状态查询的时候,读取到的就是一个一个的英文状态,不能知道是什么意思。

通用的能想到的解决方式就是:

SELECT
A.id,
A.mission_name missionName,
A.mission_status missionStatus,
CASE A.mission_status
WHEN 'init' THEN '未处理'
WHEN 'finished' THEN '已完成'
ELSE ''
END missionStatusStr
FROM ts_mission A

使用case when的方式,对返回的状态信息进行判断整理,最后返回。

这样做是没问题的,而且以我个人的编程经验来看:

不存在最好的程序,只存在符合需求的程序。

写代码也一如制造钢琴,能生产出符合需要的程序,就已经足够了。入门级别的钢琴能在2W左右买到,稍好点的,上个4-5W,也非常厉害了,但是想要达到一种完美的状态,给个100W都不够的。所以,一个程序完善了大部分的漏洞,能够在线上稳定运行就可以了。

所谓优化,也是当业务量剧增,你不得不考量成本的时候,再去做的。

上述的状态查询方式,给予了数据库额外的计算压力,而且直接将业务逻辑写在查询语句中,也是不便于后期管理维护的。

所以,至此,我提出了两个问题:

1、如何快捷方便地管理存储在行数据中的状态信息?

2、如何快捷方便地查询存储在数据行中的状态信息?

2、管理数据行的状态信息

各位要坚信,我们做程序的都是一表人才。

一表人才:不管遇到什么问题,都能通过增加一张表来解决问题的人才。

所以,我们新建一张用于存储各类状态信息的表(譬如ts_dict_data),主要存储字段状态的值(data_value),以及这个值对应的描述(data_description,也就是这个值表示什么意思),再为这张表添加一个data_code的字段,对应其他表需要存储状态的字段名称(譬如ts_mission表的mission_status),建立与ts_dict_data表的连接关系。

将所有的状态信息数据集中化管理起来,并且这样操作不会影响到以前的表设计。

3、查询数据行的状态信息

上述的方法把各个状态都抽离出来,做了集中化处理,需要添加、修改、删除什么状态,都可以在一个位置搞定。

在做web端或者app端的时候,查询某个状态的各种状态,也可以根据上述的data_code查询到对应的数据,做相应的数据操作。

那接着解决上文提及的查询问题。

在做稍微大型点的项目的时候,我们不能直接把查询的业务逻辑写在SQL语句里的。

我们对应ts_mission表的mission_status,创建一个MissionStatus的枚举类(这里针对的java语言):

package com.biz.primus.base.enums;

import com.biz.primus.common.enums.EnumerableValue;

/**
 * 任务完成状态
 * @author spirit
 * @version 1.0
 * @date 2018-09-04 17:00
 */
public enum MissionStatus implements EnumerableValue {

    /** 任务完成状态为未处理状态 */
    init(1,"未处理"),
    /** 任务完成状态为已完成状态 */
    finished(2,"已完成");

    /** 枚举对应数值 */
    private int value;
    /** 描述 */
    private String description;

    MissionStatus(int value, String description){
        this.value = value;
        this.description = description;
    }

    @Override
    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

接着创建TsMissionVo传输类,并且在这个类里面使用我们创建的枚举类型:

package com.biz.primus.base.enums;

import lombok.Data;

import java.io.Serializable;

/**
 * 任务传输类
 * @author spirit
 * @version 1.0
 * @date 2018-09-04 16:55
 */
@Data
public class TsMissionVo implements Serializable {

    /** 主键ID */
    private Long id;
    /** 任务名称 */
    private String missionName;
    /** 任务状态 */
    private MissionStatus missionStatus;
    /** 任务状态描述 */
    private String missionStatusStr;

    public void setMissionStatus(MissionStatus status) {
        this.missionStatus = status;
        if(status != null){
            this.missionStatusStr = status.getDescription();
        }
    }

}

最后,当我们在使用MyBatis做查询的时候,就不用再做前文的查询方式了(TsMissionVo是MyBatis的resultType的结果集):

SELECT
A.id,
A.mission_name missionName,
A.mission_status missionStatus
FROM ts_mission A

以上是最近在工作中悟出的一些小感想。

最后,大家有什么不懂的或者其他需要交流的内容,也可以进入我的QQ讨论群一起讨论:654331206

你可能感兴趣的:(Java,mysql)