侧边栏壁纸
博主头像
博主等级

  • 累计撰写 19 篇文章
  • 累计创建 34 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

MySql表设计规范和技巧

前尘一梦
2023-02-03 / 0 评论 / 3 点赞 / 49 阅读 / 5879 字

前言

在日常项目中,无论是系统初始架构设计还是系统上线后功能迭代, 无论是基于DDD领域驱动设计还是基于MVC的分层架构设计,最终都离不开数据建模,数据建模完成后转化为不同的数据表,此篇聊一下建表的一些规范和技巧。

必要字段

7441722686617_.pic.jpg

create_date_time、create_name、modify_date_time、modify_name 为必要字段,保存数据的基本属性,使其可追溯

is_delete 必须字段,配合MybatisPlus逻辑删除功能使用,标识数据逻辑删除,生产数据最好都不要物理删除,保留完整的现场,某些场景需要恢复已删除的数据也更简单

预留字段

description、type、state、label、sorting、version为预留字段

type:数据类型

state:状态

label:标签

sorting:排序

version:乐观锁字段,配合MybatisPlus 乐观锁功能使用或者自定义使用

基础字段封装

针对这些通用字段,可以封装在一个实体类中,给其他实体类继承,避免每个Entity冗余生成

@Getter
@Setter
public class EntityBase implements Serializable {

    @ApiModelProperty(value = "序列")
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private Long id;

    @ApiModelProperty(value = "说明")
    private String description;

    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime createDateTime;

    @ApiModelProperty(value = "创建人")
    @TableField(fill = FieldFill.INSERT)
    private String createName;

    @ApiModelProperty(value = "修改时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime modifyDateTime;

    @ApiModelProperty(value = "修改人")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private String modifyName;

    @ApiModelProperty(value = "删除状态(0:未删除,1:删除)")
    @TableLogic
    private Boolean isDelete;

    @ApiModelProperty(value = "排序")
    private Integer sorting;

    @Version
    @ApiModelProperty(hidden = true,value = "版本号")
    private Integer version;

}

@Data
@Accessors(chain = true)
@TableName("`area`")
@ApiModel(value="Area对象", description="区表")
public class Area extends EntityBase {

    @ApiModelProperty(value = "市代码")
    private String cityCode;

    @ApiModelProperty(value = "名称")
    private String name;

    @ApiModelProperty(value = "区编码")
    private String areaCode;

    @ApiModelProperty(value = "类型")
    private Integer type;

    @ApiModelProperty(value = "状态")
    private Integer state;

    @ApiModelProperty(value = "标签")
    private String label;
}

时间,操作人字段自动填充

通过实现MybatisPlus的MetaObjectHandler接口,实现通用字段自动填充,避免每次手动设值。

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Resource
    private GetUserInfo getUserInfo;

    @Override
    public void insertFill(MetaObject metaObject) {
        //第一个对应实体属性名, 第二个参数需要填充的值
        setFieldValByName("createDateTime", LocalDateTime.now(), metaObject);
        setFieldValByName("modifyDateTime", LocalDateTime.now(), metaObject);

        String currUserInfo = null;
        try {
            currUserInfo = getUserInfo.getCurrUserInfo();
        } catch (Exception e) {
        }
        currUserInfo = StringUtils.isNotBlank(currUserInfo) ? currUserInfo : "sys";
        setFieldValByName("createName", currUserInfo, metaObject);
        setFieldValByName("modifyName", currUserInfo, metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        //第一个对应实体属性名, 第二个参数需要填充的值
        setFieldValByName("modifyDateTime", LocalDateTime.now(), metaObject);
        String currUserInfo = null;
        try {
            currUserInfo = getUserInfo.getCurrUserInfo();
        } catch (Exception e) {
        }
        currUserInfo = StringUtils.isNotBlank(currUserInfo) ? currUserInfo : "sys";
        setFieldValByName("modifyName", currUserInfo, metaObject);
    }
}

public interface GetUserInfo {

    /**
     * 获取当前用户名
     */
    String getCurrUserInfo();


    /**
     * 获取登陆用户名
     */
    String getLoginName();
}

表设计常见问题

字段类型选择?

  • 常见的一些状态位字段,使用tinyint类型更省空间

  • 布尔字段使用bit类型,默认值使用b'0'

  • 如果是大型长期维护系统,主键使用bigint类型, 主键值利用雪花算法生成

  • 金额等浮点数据统一用decimal类型,小数点一般保留2位

什么时候需要中间表?

当两张表业务数据存在一对多,多对多的映射关系,适合新增一张中间表进行关联

什么时候适合冗余其他表数据?

该表查询需求较多,且需要关联查询关联表数据,关联表数据更新频率相对较低

一般的经验是,处于业务流程下游的表可以冗余上游的表数据,越是上游越适合被冗余,因为这个时候前面的流程基本已经确定,不太会修改。

总结

以上总结了一下MySql表设计的一些经验,关于CRUD代码生成可看

3

评论区