当前位置: 首页 > 科技观察

如何在不改变表结构的情况下动态扩展字段?_0

时间:2023-03-15 20:30:05 科技观察

痛点软件行业唯一不变的就是变化。比如功能上线后,客户或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'Trashtype:1:kitchentrashcan',`street_code`INT(11)DEFAULTNULLCOMMENT'位于城镇街道代码,视状态而定,这里的意思可能是使用镇街或返回镇街。',`create_time`DATETIMENOTNULLDEFAULTnow()COMMENT'创建时间',`update_time`DATETIMENOTNULLDEFAULTnow()COMMENT'更新时间',`ext`VARCHAR(1000)NOTNULLDEFAULT'{}'COMMENT'扩展字段',...PRIMARYKEY(`id`))ENGINE=InnoDBCOMMENT='垃圾桶表';Java代码:importcom.alibaba.fastjson.JSON;importlombok.Data;importjavax.validation.constraints.NotNull;importjava.util.Date;importjava.util.List;/***垃圾桶实体*CreatedbyBlinkon6/28/2018AD.**@authorBlink*/@DatapublicclassDustbin{privateStringid;/***rfid卡号*/@NotNullprivateStringrfidNo;/***垃圾桶状态:0:注销;1:未使用;2:待用;3:Used(绑定采集点);*对应Dustbin.StateEnum类*/@NotNullprivateIntegerstate;/***进入垃圾桶的人id*/@NotNullprivateLonguserId;/***garbageBuckettype:1:厨房垃圾桶*DefaultValue:1*/@NotNullprivateIntegertype;/***townstreetcode*根据状态,这里的意思可能是使用townstreet或者返回townstreet*/privateIntegerstreetCode;/***创建时间*defaultValue:now()*/@NotNullprivateDatecreateTime;/***更新时间*/@NotNullprivateDateupdateTime;/***扩展字段,见DustbinExt.java*DefaultValue:{}*/privateStringext;...publicDustbinExtgetExtObject(){returnJSON.parseObject(this.getExt(),DustbinExt.class);}publicvoidsetExtObject(DustbinExtext){this.ext=JSON.toJSONString(ext);}/***垃圾桶扩展属性*CreatedbyBlinkon6/28/2018AD.**@authorBlink*/@DatapublicstaticclassDustbinExt{/***所在的town*根据州的不同,这里的意思可能是使用townstreet,返回townstreet,或者绑定townstreet*/privateStringstreet;/***客户(采集点)id,绑定采集点时需要填写*根据当前需求(2018-06-29),采集点解绑时需要保存最新绑定的采集点名称垃圾桶的号码,所以在解绑垃圾桶的时候,不要删除*只有收集点绑定覆盖的时候*/privateLongcustomerId;/***客户(收集点)名称,需要填写在绑定收点时*根据当前需求(2018-06-29),解绑收点时*需要保存最新的垃圾桶绑定的收集点名称,所以垃圾桶未绑定时不会删除此信息*只有在绑定收集点时才覆盖他*/privateStringcustomer;/***损坏部分*1:桶盖;2:斗嘴;3:斗体;4:斗轴;5:桶底;6:斗轮;privateListparts;}...}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(数据定义语言)创建字段,非常适合解决上述问题。Java代码在这里起到了辅助作用,通过定义一个内部类来管理扩展字段的属性,方便我们对扩展字段的理解和管理,提高代码的可读性和可维护性。java的这种方法也是作者总结出来的比较优雅的做法(个人观点)。Limitations有经验的读者可能会指出ext字段在Mysql5.7.8以下版本无法索引一个或部分扩展字段,因为Mysql5.7.8以下版本不支持(Mysql5.7.8支持JsonDataType索引).MySQL数据库开发的36条军规!是的,这是此解决方案的局限性。在Mysql5.7.8以下的版本,我的建议是ext扩展字段不要存储热点数据,只存储非热点数据,这样可以避免查询操作,减少维护ext字段带来的成本和风险,如何识别新字段是否是热点数据?这个需要结合实际业务需求来判断,也可以请教业务和技术方面比较有经验的同事,让读者更快的得出结论。终极解决方案在一些极端的情况下,变化可能来得太快,而我们想要的是降低变化带来的成本和风险,所以在表设计之初,我们可以利用自己的经验或者找更有经验的人寻求帮助,估计需要预留多少备用字段,配合扩展字段,基本上可以把表结构的改动(加字段)次数减少到极小的次数。总结一下,在特殊情况下,通过扩展字段+保留字段,基本可以在不影响热点数据索引的情况下动态扩展字段。这样,我们得到了一个非常灵活的表结构,方便我们处理以后的Change,但是请注意,我们必须维护我们的实体,包括里面的每一个字段,尊重每一行代码。最后关注公众号Java技术栈,后台回复:面试,可以拿到我整理的MySQL系列面试题及答案,很全。