MySQL讀取JSON轉(zhuǎn)換的方式
存儲(chǔ)
mysql5.7+開(kāi)始支持存儲(chǔ)JSON,后續(xù)不斷優(yōu)化,應(yīng)用也越來(lái)越廣泛 你可以自己將數(shù)據(jù)轉(zhuǎn)換成Json String后插入,也可以選擇使用工具, 而mybatis-plus就為此提供了非常簡(jiǎn)便的方式, 只需要在字段上加上 @TableField(typeHandler = XxxTypeHandler.class), mybatis-plus就會(huì)自動(dòng)幫你做轉(zhuǎn)換,通用一般就兩個(gè): - com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler - com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler
例如
@Data @TableName(autoResultMap = true) public class Department implements Serializable { private static final long serialVersionUID = 203788572415896870L; @TableField(typeHandler = FastjsonTypeHandler.class) private List<Integer> userIds; }
存在什么問(wèn)題?
如果使用通用處理器,那對(duì)于基礎(chǔ)類型以及對(duì)象來(lái)說(shuō)沒(méi)有什么問(wèn)題。 但如果存儲(chǔ)的字段類型是對(duì)象集合,那么當(dāng)你取出來(lái)時(shí),會(huì)發(fā)現(xiàn)集合中的對(duì)象都是JSONObject類型。 最常見(jiàn)的情況就拿出來(lái)進(jìn)行遍歷操作時(shí),會(huì)拋出強(qiáng)轉(zhuǎn)異常: java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to ... 因?yàn)樘幚砥鲙湍戕D(zhuǎn)換時(shí),并不會(huì)存儲(chǔ)你集合的泛型,所以統(tǒng)統(tǒng)都按照Object類型來(lái)轉(zhuǎn)換了: @Override protected Object parse(String json) { return JSON.parseObject(json, type); }
例如下面這種形式的類:
@Data @TableName(autoResultMap = true) public class Department implements Serializable { private static final long serialVersionUID = 203788572415896870L; @TableId(value = "id", type = IdType.AUTO) private Integer id; @TableField(typeHandler = FastjsonTypeHandler.class) private List<User> users; @Data public static class USer implements Serializable { // ... } }
如何處理
方式一:自定義處理器,自己做類型轉(zhuǎn)換,這也是當(dāng)前最普遍的方式,但是對(duì)于存在List字段的對(duì)象,還需要在XxxMapper.xml中進(jìn)行resultMap配置
@MappedTypes({Object.class}) @MappedJdbcTypes(JdbcType.VARCHAR) public class ListFastJsonTypeHandler extends FastjsonTypeHandler { private final Class<? extends Object> type; public ListFastJsonTypeHandler(Class<?> type) { super(type); this.type = type; } /** * 自己將json轉(zhuǎn)換成list * @param json * @return */ @Override protected Object parse(String json) { return JSON.parseArray(json, this.type); }
<mapper namespace="com.xxx.cn.mapper.DepartmentMapper"> <resultMap id="BaseResultMap" type="com.xxx.cn.domain.Department"> <id property="id" column="id"/> <result property="users" column="users" jdbcType="VARCHAR" javaType="com.xxx.cn.domain.Department.User" typeHandler="com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler"/> </resultMap> </mapper>
配置完成后,ListFastJsonTypeHandler就會(huì)將json轉(zhuǎn)換成javaType對(duì)應(yīng)的對(duì)象集合了
方式二:配置一個(gè)Mybatis插件,攔截ResultSetHandler,將返回結(jié)果進(jìn)行處理。 這樣的好處就是不用寫自定義的處理器和在XxxMapper.xml中做配置,減少了工作
@Component @Intercepts({ @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class}) }) public class ResultSetInterceptor implements Interceptor { /** * json序列化規(guī)則 */ private final SerializerFeature[] serializerFeatures = { SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteNullStringAsEmpty }; @Override public Object intercept(Invocation invocation) throws Throwable { Object proceed = invocation.proceed(); if (containJSONObject(proceed)) { if (proceed instanceof Collection) { return JSON.parseArray(JSON.toJSONString(proceed, serializerFeatures), ((Collection<?>) proceed).toArray()[0].getClass()); } return JSON.parseObject(JSON.toJSONString(proceed, serializerFeatures), proceed.getClass()); } // if (proceed instanceof Collection) { // for (Object obj : ((Collection<?>) proceed)) { // parseJSON2Object(obj, obj.getClass()); // } // } else { // parseJSON2Object(proceed, proceed.getClass()); // } return proceed; } * 將返回?cái)?shù)據(jù)中心的JSONObject對(duì)象轉(zhuǎn)換成正常的對(duì)象 * * @param obj * @param typeClass * @throws IllegalAccessException * @throws ClassNotFoundException private void parseJSON2Object(Object obj, Class<?> typeClass) throws IllegalAccessException, ClassNotFoundException { for (Field declaredField : typeClass.getDeclaredFields()) { declaredField.setAccessible(true); Object value = declaredField.get(obj); if (isNullValueField(value)) { continue; Type genericType = declaredField.getGenericType(); String fieldClassName = genericType.getTypeName(); if (genericType instanceof ParameterizedType) { fieldClassName = ((ParameterizedType) genericType).getActualTypeArguments()[0].getTypeName(); if (containJSONObject(value)) { if (value instanceof Collection) { declaredField.set(obj, JSON.parseArray(JSON.toJSONString(value, serializerFeatures), Class.forName(fieldClassName))); } else { declaredField.set(obj, JSON.parseObject(JSON.toJSONString(value, serializerFeatures), Class.forName(fieldClassName))); } * 判斷是否跳過(guò)字段 * @param value * @return private Boolean isNullValueField(Object value) { return null == value || "".equals(String.valueOf(value).trim()) || (value instanceof Collection && ((Collection<?>) value).size() == 0); * 判斷值是否包含JSONObject對(duì)象 private boolean containJSONObject(Object value) throws IllegalAccessException { if (isNullValueField(value)) { return false; if (value instanceof Collection) { for (Object obj : (Collection<?>) value) { if (obj instanceof JSONObject) { return true; if (obj instanceof Collection && containJSONObject(obj)) { for (Field declaredField : obj.getClass().getDeclaredFields()) { declaredField.setAccessible(true); Object fieldValue = declaredField.get(obj); if (isNullValueField(fieldValue)) { continue; } if (fieldValue instanceof JSONObject) { return true; if (fieldValue instanceof Collection && containJSONObject(fieldValue)) { } return value instanceof JSONObject; }
到此這篇關(guān)于MySQL讀取JSON轉(zhuǎn)換的文章就介紹到這了,更多相關(guān)MySQL讀取JSON轉(zhuǎn)換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
從底層簡(jiǎn)析Python程序的執(zhí)行過(guò)程
這篇文章主要介紹了從底層簡(jiǎn)析Python程序的執(zhí)行過(guò)程,包括注入操作碼和封裝程序等解釋器執(zhí)行層面的知識(shí),需要的朋友可以參考下2015-06-06一次現(xiàn)場(chǎng)mysql重復(fù)記錄數(shù)據(jù)的排查處理實(shí)戰(zhàn)記錄
這篇文章主要給大家介紹了一次現(xiàn)場(chǎng)mysql重復(fù)記錄數(shù)據(jù)的排查處理記錄,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-10-10MySQL之終端Terminal(dos界面)管理數(shù)據(jù)庫(kù)、數(shù)據(jù)表、數(shù)據(jù)的基本操作
這篇文章主要介紹了MySQL之終端(Terminal)管理數(shù)據(jù)庫(kù)、數(shù)據(jù)表、數(shù)據(jù)的基本操作,需要的朋友可以參考下2015-03-03Mysql之EXPLAIN顯示using filesort介紹
EXPLAIN 是mysql解釋select查詢的一個(gè)關(guān)鍵字,可以很方便的用于調(diào)試2012-02-02Mysql更換MyISAM存儲(chǔ)引擎為Innodb的操作記錄總結(jié)
下面小編就為大家?guī)?lái)一篇Mysql更換MyISAM存儲(chǔ)引擎為Innodb的操作記錄總結(jié)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03Linux環(huán)境下安裝mysql5.7.36數(shù)據(jù)庫(kù)教程
大家好,本篇文章主要講的是Linux環(huán)境下安裝mysql5.7.36數(shù)據(jù)庫(kù)教程,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12Canal監(jiān)聽(tīng)MySQL的實(shí)現(xiàn)步驟
本文主要介紹了Canal監(jiān)聽(tīng)MySQL的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08MySQL設(shè)置管理員密碼無(wú)法生效的問(wèn)題解析
這篇文章主要介紹了MySQL設(shè)置管理員密碼無(wú)法生效的問(wèn)題解析,一般在遇到?MySQL?問(wèn)題時(shí),建議對(duì)?MySQL?系統(tǒng)函數(shù)、數(shù)據(jù)庫(kù)內(nèi)部對(duì)象等進(jìn)行檢索而不是直接打印字符串,有時(shí)候可能對(duì)快速定位問(wèn)題原因有幫助,需要的朋友可以參考下2022-06-06