乐趣区

关于java:如何不改表结构动态扩展字段

作者:李瑜宁

起源:https://juejin.cn/post/684490…

笔者的动静字段扩大解决方案次要针对 Mysql 5.7.8 以下版本,在 Mysql 5.7.8 曾经新增 JSON Data Type,同样实用该计划,而且状况变得更加简略。

痛点

软件行业惟一不变的就是变动,比方性能上线之后,客户或 PM 须要对已有的性能减少一些正当的需要,实现这些工作必须通过增加字段解决,或者某些性能的实现须要通过减少字段来升高实现的复杂性等等。

这些问题都会改变线上的数据库表构造,一旦改变就会导致锁表,会使所有的写入操作始终期待,直到表锁敞开,特地是对于数据量大的热点表,增加一个字段可能会因为锁表工夫过长而导致局部申请超时,这可能会 对企业间接造成经济上的损失

解决方案

减少 json 格局的扩大字段。

上面配合一些代码来形容这个解决方案,读者便于去了解。

mysql 数据库脚本:

DROP TABLE IF EXISTS `cs_dustbin`;
CREATE TABLE IF NOT EXISTS `cs_dustbin` (`id` VARCHAR(45) NOT NULL COMMENT '主键自增 id',
  `rfid_no` VARCHAR(20) NOT NULL COMMENT 'rfid 卡号',
  `state` INT(1) NOT NULL COMMENT '垃圾桶状态:0:已登记;1:未应用;2:待应用;3:已应用(绑定收集点);',
  `user_id` INT NOT NULL COMMENT '注销人,负责录入垃圾桶的人',
  `type` INT(1) NOT NULL DEFAULT 1 COMMENT '垃圾桶类型:1:餐厨垃圾桶',
  `street_code` INT(11) DEFAULT NULL COMMENT '所在镇街 code,依据状态,这里的含意可能是领用镇街、退还镇街。',
  `create_time` DATETIME NOT NULL DEFAULT now() COMMENT '创立工夫',
  `update_time` DATETIME NOT NULL DEFAULT now() COMMENT '更新工夫',
  `ext` VARCHAR(1000) NOT NULL DEFAULT '{}' COMMENT '扩大字段',
  ...
  PRIMARY KEY (`id`))
ENGINE = InnoDB
COMMENT = '垃圾桶表';

Java 代码:

import com.alibaba.fastjson.JSON;
import lombok.Data;

import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.List;

/**
 * 垃圾桶实体
 * Created by Blink on 6/28/2018 AD.
 *
 * @author Blink
 */
@Data
public class Dustbin {

    private String id;

    /**
     * rfid 卡号
     */
    @NotNull
    private String rfidNo;

    /**
     * 垃圾桶状态:0:已登记;1:未应用;2:待应用;3:已应用(绑定收集点);* 对应 Dustbin.StateEnum 类
     */
    @NotNull
    private Integer state;

    /**
     * 录入垃圾桶的人员 id
     */
    @NotNull
    private Long userId;

    /**
     * 垃圾桶类型:1:餐厨垃圾桶
     * DefaultValue: 1
     */
    @NotNull
    private Integer type;

    /**
     * 所在镇街 code
     * 依据状态,这里的含意可能是领用镇街、退还镇街
     */
    private Integer streetCode;

    /**
     * 创立工夫
     * defaultValue : now()
     */
    @NotNull
    private Date createTime;

    /**
     * 更新工夫
     */
    @NotNull
    private Date updateTime;

    /**
     * 扩大字段,具体数据查看 DustbinExt.java
     * DefaultValue: {}
     */
    private String ext;

    ...

    public DustbinExt getExtObject() {return JSON.parseObject(this.getExt(), DustbinExt.class);
    }

    public void setExtObject(DustbinExt ext) {this.ext = JSON.toJSONString(ext);
    }

    /**
     * 垃圾桶扩大属性
     * Created by Blink on 6/28/2018 AD.
     *
     * @author Blink
     */
    @Data
    public static class DustbinExt {

        /**
         * 所在镇街
         * 依据状态,这里的含意可能是领用镇街、退还镇街、绑定的镇街
         */

        private String street;

        /**
         * 客户(收集点)id,绑定收集点的时候须要填入
         * 依据目前的需要(2018-06-29),当收集点解绑的时候
         * 须要保留垃圾桶最新绑定收集点名称,所以在解绑垃圾桶的时候不会把这个信息删掉
         * 只有当绑定收集点的时候才把他笼罩
         */
        private Long customerId;

        /**
         * 客户(收集点)名称,绑定收集点的时候须要填入
         * 依据目前的需要(2018-06-29),当收集点解绑的时候
         * 须要保留垃圾桶最新绑定收集点名称,所以在解绑垃圾桶的时候不会把这个信息删掉
         * 只有当绑定收集点的时候才把他笼罩
         */
        private String customer;

        /**
         * 损坏部位
         * 1:桶盖;2:桶口;3:桶身;4:桶轴;5:桶底;6:桶轮;* 对应 DustbinDamagePartEnum 类
         */
        private List<Integer> parts;
    }

    ...
}

mysql 脚本能够看到扩大字段的信息:

ext VARCHAR(1000) NOT NULL DEFAULT '{}' COMMENT '扩大字段'

能够看到这么一段 Java 代码:

...

/**
 * 扩大字段,具体字段查看 DustbinExt 类
 * DefaultValue: {}
 */
private String ext;

public DustbinExt getExtObject() {return JSON.parseObject(this.getExt(), DustbinExt.class);
}

public void setExtObject(DustbinExt ext) {this.ext = JSON.toJSONString(ext);
}

...

能够看到 ext 字段就是用来存储 json 格局的数据,它能够动静地减少任何字段,甚至是对象,不须要通过 DDL(Data Definition Language)去创立字段,非常适合用来解决下面提到的问题。

Java 代码在这里起到辅助性作用,通过定义一个外部类来治理扩大字段的属性,不便咱们理解和治理扩大字段,进步代码的可读性和可维护性,java 这种形式也是笔者总结进去的较为优雅的做法(个人观点)。

局限性

有教训的读者可能会提出,ext 字段在 Mysql 5.7.8 以下版本无奈对扩大字段中的某一个或一部分字段建设索引,因为 Mysql 5.7.8 版本以下不反对(Mysql 5.7.8 反对为 Json Data Type 建设索引)。

没错,这是这个解决方案的一个局限性,在 Mysql 5.7.8 以下版本,我的倡议是,ext 扩大字段不要存储热点数据,只存储非热点数据,这样就能够防止查问操作,升高保护 ext 字段带来的老本和危险,那如何辨认新增字段是不是热点数据呢?这个须要结合实际业务需要来判断,也能够询问对业务和技术更有教训的共事,便于读者更快得出结论。

终极版解决方案

在一些极其的状况下,变动可能来得太快,而咱们要的是缩小变动带来的老本和危险,所以在表设计之初能够依据本身教训,或者找更有教训的人寻求帮忙,预估一下须要预留多少个备用字段,再配合扩大字段,基本上能够把扭转(增加字段)表构造的次数降至一个非常少的次数。

总结

在非凡状况下,通过扩大字段 + 预留字段基本上能够做到动静扩大字段,又不会影响为热点数据建设索引的状况,这样咱们失去了一个非常灵活的表构造,便于咱们应答将来的变动,然而请留神,要保护好咱们的实体,包含外面的每一个字段,敬畏每一行代码。

近期热文举荐:

1.1,000+ 道 Java 面试题及答案整顿(2021 最新版)

2. 终于靠开源我的项目弄到 IntelliJ IDEA 激活码了,真香!

3. 阿里 Mock 工具正式开源,干掉市面上所有 Mock 工具!

4.Spring Cloud 2020.0.0 正式公布,全新颠覆性版本!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

退出移动版