Mysql?json類(lèi)型字段Java+Mybatis數(shù)據(jù)字典功能的實(shí)踐方式
前言
JSON類(lèi)型是MySQL5.7.8中新加入的一種數(shù)據(jù)類(lèi)型,并在后續(xù)版本尤其是MySQL8.0中得到了大幅增強(qiáng),現(xiàn)在的JSON類(lèi)型的功能十分強(qiáng)大,合理使用能讓我們的開(kāi)發(fā)更加有效!
但本文不準(zhǔn)備花篇幅來(lái)介紹MySQL的JSON類(lèi)型字段的相關(guān)API,因?yàn)楣俜轿臋n里面寫(xiě)得已經(jīng)十分詳細(xì)了,大家如果對(duì)MySQL的JSON類(lèi)型還不怎么了解的話(huà)可以看看官方文檔:
- MySQL5.7 JSON功能介紹:https://dev.mysql.com/doc/refman/5.7/en/mysql-nutshell.html (搜 JSON support)
- MySQL8.0 JSON增強(qiáng)說(shuō)明:https://dev.mysql.com/doc/refman/8.0/en/mysql-nutshell.html (搜 JSON enhanc)
- MySQL8.0 JSON功能介紹:https://dev.mysql.com/doc/refman/8.0/en/json.html
(ps:英語(yǔ)相對(duì)較差的小伙伴可以用chrome瀏覽器打開(kāi),然后用自帶的翻譯工具翻譯后看哦~)
應(yīng)用場(chǎng)景介紹
JSON的應(yīng)用場(chǎng)景還是挺多的,我能想到的兩個(gè)是:
數(shù)據(jù)字典
- 基本上所有系統(tǒng)都會(huì)有數(shù)據(jù)字典,比如各種下拉框的內(nèi)容,這種數(shù)據(jù)如果需要支持讓用戶(hù)自定義,那么基本上就是使用數(shù)據(jù)字典,而字典內(nèi)容則是標(biāo)準(zhǔn)的JSON對(duì)象,用JSON保存再好不過(guò)!
動(dòng)態(tài)表單
- 如一些信息收集的表單,需要提供用戶(hù)自定義信息時(shí),這些信息也是JSON對(duì)象,也可以通過(guò)JSON字段保存。
數(shù)據(jù)字典案例實(shí)踐
- 本文將針對(duì)數(shù)據(jù)字典使用JSON類(lèi)型案例進(jìn)行詳細(xì)介紹,本文中使用的ORM框架是Mybatis,其他ORM框架應(yīng)該也大同小異。如果其他框架使用出現(xiàn)問(wèn)題,可以留言一起討論哦~
- 本文中還是用了Swagger、Mybatis Plus、Lombok等工具,如果這些還不熟悉的可以先去做做功課哦,這些都是開(kāi)發(fā)中非常強(qiáng)大而給力的工具,讓我們編碼時(shí)如虎添翼,效率翻倍~
功能方面需要明確的是:
枚舉選項(xiàng)是嚴(yán)禁直接刪除的。
- 字典內(nèi)容只能增加不能減少,因?yàn)橐坏﹦h除一個(gè)選項(xiàng),會(huì)導(dǎo)致?lián)碛羞@個(gè)選項(xiàng)的數(shù)據(jù)無(wú)法找到對(duì)應(yīng)枚舉,導(dǎo)致顯示異常。
- 當(dāng)然,如果非要有刪除功能,我們也能像表數(shù)據(jù)那樣增加一個(gè)邏輯刪除功能。
枚舉選項(xiàng)的鍵是嚴(yán)禁修改的。
- 這個(gè)就不用過(guò)多解釋了,鍵就相當(dāng)于表的ID一樣,肯定是不允許修改的,用于展示的值可修改。
可以增加一些輔助功能。
- 可以對(duì)選項(xiàng)增加一個(gè)排序功能,讓客戶(hù)能自定義排序。
- 可以增加創(chuàng)建修改信息字段,記錄選項(xiàng)改動(dòng)信息。
表結(jié)構(gòu)
CREATE TABLE `sys_dict` ( `id` int(11) NOT NULL AUTO_INCREMENT, `code` varchar(30) NOT NULL COMMENT '編碼', `name` varchar(40) NOT NULL COMMENT '展示名稱(chēng)', `content` json NOT NULL COMMENT '內(nèi)容', /* 下面六個(gè)字段根據(jù)需要增加 */ `description` varchar(200) DEFAULT NULL COMMENT '描述', `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否刪除 [0未刪除 1已刪除]', `create_by` int(11) DEFAULT NULL COMMENT '創(chuàng)建人', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間', `update_by` int(11) DEFAULT NULL COMMENT '修改人', `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改時(shí)間', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系統(tǒng)字典表';
實(shí)體類(lèi)
@Getter @Setter @TableName(value = "sys_dict", autoResultMap = true) @ApiModel("系統(tǒng)字典實(shí)體類(lèi)") public class SysDict extends BaseDO { @TableId(type = IdType.AUTO) //id自增 private Integer id; @ApiModelProperty("編碼") private String code; @ApiModelProperty("名稱(chēng)") private String name; @TableField(typeHandler = JacksonTypeHandler.class) @ApiModelProperty("內(nèi)容列表") private List<DictContent> content; @Getter @Setter @NoArgsConstructor @ApiModel("系統(tǒng)字典內(nèi)容實(shí)體類(lèi)") public static class DictContent { @ApiModelProperty("鍵") private Integer key; @ApiModelProperty("值") private String value; @ApiModelProperty("排序,數(shù)字越小越前面") private Integer order; @ApiModelProperty("是否刪除 [0:未刪除 1:已刪除]") private Integer deleted; //輔助字段根據(jù)需求來(lái)定,有必要的情況下可以繼承BaseDO,增加那6個(gè)字段! } } @Getter @Setter public abstract class BaseDO implements Serializable { @ApiModelProperty("備注") private String description; @ApiModelProperty("是否刪除 [0:未刪除 1:已刪除]") private Integer deleted; @ApiModelProperty("創(chuàng)建人") private Integer createBy; //JSONFormat是格式化時(shí)間的輸入輸出格式 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh", timezone = "GMT+8") @ApiModelProperty("創(chuàng)建時(shí)間") private LocalDateTime createTime; @ApiModelProperty("修改人") private Integer updateBy; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh", timezone = "GMT+8") @ApiModelProperty("修改時(shí)間") private LocalDateTime updateTime; }
這里為了方便,將創(chuàng)建修改信息等6個(gè)字段抽象出來(lái)了,以后創(chuàng)建實(shí)體類(lèi)就直接繼承該類(lèi)就行,同時(shí)該類(lèi)聲明了序列化,所以其子類(lèi)也不需要再單獨(dú)實(shí)現(xiàn)Serializable接口,一舉多得~
這里有兩個(gè)個(gè)細(xì)節(jié):
- 將BaseDO類(lèi)聲明成抽象類(lèi):如果不聲明成抽象類(lèi)的話(huà),在絲襪哥(Swagger)接口文檔中就只會(huì)顯示父類(lèi)BaseDO的信息,不會(huì)顯示其子類(lèi)信息。(我之前就是沒(méi)有聲明成抽象類(lèi),出現(xiàn)了這個(gè)問(wèn)題,糾結(jié)了一陣。。。)
- 將內(nèi)部類(lèi)DictContent用static修飾:如果用static修飾的話(huà),其他地方就無(wú)法直接使用該類(lèi)的構(gòu)造方法;在查詢(xún)數(shù)據(jù)時(shí),Mybatis就無(wú)法實(shí)例化該對(duì)象,會(huì)報(bào)錯(cuò)的哦。
關(guān)系映射
通過(guò)Mybatis Plus注解實(shí)現(xiàn)
上文中的@TableName和@TableField是Mybatis Plus提供的注解,@TableName的autoResultMap屬性一般與content字段的@TableField的typeHandler屬性一起使用,表示會(huì)自動(dòng)創(chuàng)建resultMap處理查詢(xún)返回值,但這個(gè)操作僅限于Mybatis Plus提供的查詢(xún)方法,自定義方法不會(huì)自動(dòng)創(chuàng)建。
通過(guò)ResultMap實(shí)現(xiàn)
需要注意的是:如果你在對(duì)應(yīng)的Mapper文件中自定義了類(lèi)型為這個(gè)實(shí)體類(lèi)的ResultMap的話(huà),上述操作也不會(huì)執(zhí)行。也就是說(shuō)如果需要自定義ResultMap,則需要手動(dòng)增加typeHandler屬性:
沒(méi)有使用Mybatis Plus的小伙伴也是通過(guò)下述這種方式進(jìn)行類(lèi)型轉(zhuǎn)換~~
<!-- 通用查詢(xún)映射結(jié)果 --> <resultMap id="BaseResultMap" type="com.copm.ifm.servers.insp.entity.SysDict"> <id column="id" property="id" /> <result column="code" property="code" /> <result column="name" property="name" /> <!-- 這里顯示指定typeHandler屬性值 --> <result column="content" property="content" jdbcType="JAVA_OBJECT" javaType="java.util.List" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/> <result column="description" property="description" /> <result column="deleted" property="deleted" /> <result column="create_by" property="createBy" /> <result column="create_time" property="createTime" /> <result column="update_by" property="updateBy" /> <result column="update_time" property="updateTime" /> </resultMap>
上述代碼中使用的jdbcType="JAVA_OBJECT"中,jdbcType的取值范圍來(lái)源于org.apache.ibatis.type.JdbcType枚舉。
content的javaType不要寫(xiě)成了SysDict#DictContent 哦!他的java類(lèi)型是List,DictContent是List的泛型。
只要存在type=“com.copm.ifm.servers.insp.entity.SysDict” 的resultMap,就會(huì)使Mybatis Plus的 @TableName(autoResultMap = true) 失效。
泛型擦除問(wèn)題解決(7.21新增)
昨天在實(shí)際應(yīng)用過(guò)程中遇到了泛型擦除問(wèn)題,如下圖,content字段List的泛型明明是DictContent,但是其實(shí)際泛型卻是LinkedHashMap!所以在后面的遍歷時(shí)報(bào)類(lèi)型轉(zhuǎn)換失敗的錯(cuò),這就是典型的泛型擦除問(wèn)題!
詳細(xì)解決方案請(qǐng)看:>>泛型擦除問(wèn)題解決傳送門(mén)<<
解決方案1:
自定義一個(gè)指定泛型的集合類(lèi)替代List<T>即可。
8.11新增:解決方案2:
效果展示
本文通過(guò)swagger文檔添加操作進(jìn)行效果展示
總結(jié)
JSON類(lèi)型的功能十分強(qiáng)大,可以通過(guò)MySQL提供的JSON相關(guān)的方法直接操作JSON字段中的某個(gè)屬性值,也可以針對(duì)JSON類(lèi)型字段的數(shù)據(jù)進(jìn)行各種操作。
相對(duì)于使用字符串類(lèi)型保存JSON字符串的方式而言,使用JSON類(lèi)型的另外一個(gè)好處是可以在程序上定義JSON格式,提供更友好而規(guī)范的API文檔。
另外如果不想使用JSON類(lèi)型,直接用Varchar類(lèi)型也是可以的哦!如果用JSON類(lèi)型可以根據(jù)JSON對(duì)象的字段進(jìn)行條件查詢(xún)!
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Mysql如何對(duì)json數(shù)據(jù)進(jìn)行查詢(xún)及修改
- MySQL中JSON字段數(shù)據(jù)類(lèi)型詳解
- Mysql怎么存儲(chǔ)json格式數(shù)據(jù)詳解
- mysql根據(jù)json字段內(nèi)容作為查詢(xún)條件(包括json數(shù)組)檢索數(shù)據(jù)
- Mysql將查詢(xún)結(jié)果集轉(zhuǎn)換為JSON數(shù)據(jù)的實(shí)例代碼
- 使用python將mysql數(shù)據(jù)庫(kù)的數(shù)據(jù)轉(zhuǎn)換為json數(shù)據(jù)的方法
- 用Python將mysql數(shù)據(jù)導(dǎo)出成json的方法
- MySQL查詢(xún)和篩選存儲(chǔ)的JSON數(shù)據(jù)的操作方法
相關(guān)文章
SpringBoot中dubbo+zookeeper實(shí)現(xiàn)分布式開(kāi)發(fā)的應(yīng)用詳解
這篇文章主要介紹了SpringBoot中dubbo+zookeeper實(shí)現(xiàn)分布式開(kāi)發(fā)的應(yīng)用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11Lombok插件有望被Intellij IDEA收編以改善兼容性問(wèn)題(推薦)
這篇文章主要介紹了Lombok插件有望被Intellij IDEA收編以改善兼容性問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08java使用compareTo實(shí)現(xiàn)一個(gè)類(lèi)的對(duì)象之間比較大小操作
這篇文章主要介紹了java使用compareTo實(shí)現(xiàn)一個(gè)類(lèi)的對(duì)象之間比較大小操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09async-excel實(shí)現(xiàn)多sheet異步導(dǎo)出方法詳解
這篇文章主要介紹了async-excel實(shí)現(xiàn)多sheet異步導(dǎo)出方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-12-12Spring占位符Placeholder的實(shí)現(xiàn)原理解析
這篇文章主要介紹了Spring占位符Placeholder的實(shí)現(xiàn)原理,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03