2022-10-27 460
软件行业唯一不变的就是变化,比如功能上线之后,客户或 PM 需要对已有的功能增加一些合理的需求,完成这些工作必须通过添加字段解决,或者某些功能的实现需要通过增加字段来降低实现的复杂性等等。
这些问题都会改动线上的数据库表结构,一旦改动就会导致锁表,会使所有的写入操作一直等待,直到表锁关闭,特别是对于数据量大的热点表,添加一个字段可能会因为锁表时间过长而导致部分请求超时,这可能会对企业间接造成经济上的损失。
增加 json 格式的扩展字段。
下面配合一些代码来描述这个解决方案,读者便于去理解。另外,MySQL 系列面试题和答案全部整理好了,微信搜索Java技术栈,在后台发送:面试,可以在线阅读。
mysql 数据库脚本:
DROPTABLEIFEXISTS`cs_dustbin`; CREATETABLEIFNOTEXISTS`cs_dustbin`( `id`VARCHAR(45)NOTNULLCOMMENT'主键自增id', `rfid_no`VARCHAR(20)NOTNULLCOMMENT'rfid卡号', `state`INT(1)NOTNULLCOMMENT'垃圾桶状态:0:已注销;1:未使用;2:待使用;3:已使用(绑定收集点);', `user_id`INTNOTNULLCOMMENT'登记人,负责录入垃圾桶的人', `type`INT(1)NOTNULLDEFAULT1COMMENT'垃圾桶类型:1:餐厨垃圾桶', `street_code`INT(11)DEFAULTNULLCOMMENT'所在镇街code,根据状态,这里的含义可能是领用镇街、退还镇街。', `create_time`DATETIMENOTNULLDEFAULTnow()COMMENT'创建时间', `update_time`DATETIMENOTNULLDEFAULTnow()COMMENT'更新时间', `ext`VARCHAR(1000)NOTNULLDEFAULT'{}'COMMENT'扩展字段', ... PRIMARYKEY(`id`)) ENGINE=InnoDB COMMENT='垃圾桶表';
Java 代码:
importcom.alibaba.fastjson.JSON; importlombok.Data; importjavax.validation.constraints.NotNull; importjava.util.Date; importjava.util.List; /** *垃圾桶实体 *CreatedbyBlinkon6/28/2018AD. * *@authorBlink */ @Data publicclassDustbin{ privateStringid; /** *rfid卡号 */ @NotNull privateStringrfidNo; /** *垃圾桶状态:0:已注销;1:未使用;2:待使用;3:已使用(绑定收集点); *对应Dustbin.StateEnum类 */ @NotNull privateIntegerstate; /** *录入垃圾桶的人员id */ @NotNull privateLonguserId; /** *垃圾桶类型:1:餐厨垃圾桶 *DefaultValue:1 */ @NotNull privateIntegertype; /** *所在镇街code *根据状态,这里的含义可能是领用镇街、退还镇街 */ privateIntegerstreetCode; /** *创建时间 *defaultValue:now() */ @NotNull privateDatecreateTime; /** *更新时间 */ @NotNull privateDateupdateTime; /** *扩展字段,详细数据查看DustbinExt.java *DefaultValue:{} */ privateStringext; ... publicDustbinExtgetExtObject(){ returnJSON.parseObject(this.getExt(),DustbinExt.class); } publicvoidsetExtObject(DustbinExtext){ this.ext=JSON.toJSONString(ext); } /** *垃圾桶扩展属性 *CreatedbyBlinkon6/28/2018AD. * *@authorBlink */ @Data publicstaticclassDustbinExt{ /** *所在镇街 *根据状态,这里的含义可能是领用镇街、退还镇街、绑定的镇街 */ privateStringstreet; /** *客户(收集点)id,绑定收集点的时候需要填入 *根据目前的需求(2018-06-29),当收集点解绑的时候 *需要保存垃圾桶最新绑定收集点名称,所以在解绑垃圾桶的时候不会把这个信息删掉 *只有当绑定收集点的时候才把他覆盖 */ privateLongcustomerId; /** *客户(收集点)名称,绑定收集点的时候需要填入 *根据目前的需求(2018-06-29),当收集点解绑的时候 *需要保存垃圾桶最新绑定收集点名称,所以在解绑垃圾桶的时候不会把这个信息删掉 *只有当绑定收集点的时候才把他覆盖 */ privateStringcustomer; /** *损坏部位 *1:桶盖;2:桶口;3:桶身;4:桶轴;5:桶底;6:桶轮; *对应DustbinDamagePartEnum类 */ privateList<Integer>parts; } ... }
mysql 脚本可以看到扩展字段的信息:
extVARCHAR(1000)NOTNULLDEFAULT'{}'COMMENT'扩展字段'
可以看到这么一段 Java 代码:
... /** *扩展字段,详细字段查看DustbinExt类 *DefaultValue:{} */ privateStringext; publicDustbinExtgetExtObject(){ returnJSON.parseObject(this.getExt(),DustbinExt.class); } publicvoidsetExtObject(DustbinExtext){ 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数据库开发的 36 条军规!
没错,这是这个解决方案的一个局限性,在 Mysql 5.7.8 以下版本,我的建议是, ext 扩展字段不要存储热点数据,只存储非热点数据,这样就可以避免查询操作,降低维护 ext 字段带来的成本和风险,那如何识别新增字段是不是热点数据呢?
这个需要结合实际业务需求来判断,也可以询问对业务和技术更有经验的同事,便于读者更快得出结论。
在一些极端的情况下,变化可能来得太快,而我们要的是减少变化带来的成本和风险,所以在表设计之初可以根据自身经验,或者找更有经验的人寻求帮助,预估一下需要预留多少个备用字段,再配合扩展字段,基本上可以把改变(添加字段)表结构的次数降至一个非常少的次数。
在特殊情况下,通过扩展字段 + 预留字段基本上可以做到动态扩展字段,又不会影响为热点数据建立索引的情况,这样我们得到了一个非常灵活的表结构,便于我们应对未来的变化,但是请注意,要维护好我们的实体,包括里面的每一个字段,敬畏每一行代码。
最后,关注公众号Java技术栈,在后台回复:面试,可以获取我整理的 MySQL 系列面试题和答案,非常齐全。
原文链接:https://77isp.com/post/10669.html
=========================================
https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。
数据库技术 2022-03-28
网站技术 2022-11-26
网站技术 2023-01-07
网站技术 2022-11-17
Windows相关 2022-02-23
网站技术 2023-01-14
Windows相关 2022-02-16
Windows相关 2022-02-16
Linux相关 2022-02-27
数据库技术 2022-02-20
抠敌 2023年10月23日
嚼餐 2023年10月23日
男忌 2023年10月22日
瓮仆 2023年10月22日
簿偌 2023年10月22日
扫码二维码
获取最新动态