MySQL读取JSON转换的方式


Posted in MySQL onMarch 18, 2022

存储

mysql5.7+开始支持存储JSON,后续不断优化,应用也越来越广泛
你可以自己将数据转换成Json String后插入,也可以选择使用工具,
而mybatis-plus就为此提供了非常简便的方式,
只需要在字段上加上 @TableField(typeHandler = XxxTypeHandler.class),
mybatis-plus就会自动帮你做转换,通用一般就两个:
   - 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;
}

存在什么问题?

如果使用通用处理器,那对于基础类型以及对象来说没有什么问题。
但如果存储的字段类型是对象集合,那么当你取出来时,会发现集合中的对象都是JSONObject类型。
最常见的情况就拿出来进行遍历操作时,会抛出强转异常:
    java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to ...
因为处理器帮你转换时,并不会存储你集合的泛型,所以统统都按照Object类型来转换了:
    @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 {
        // ...
    }
}

如何处理

方式一:自定义处理器,自己做类型转换,这也是当前最普遍的方式,但是对于存在List字段的对象,还需要在XxxMapper.xml中进行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转换成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就会将json转换成javaType对应的对象集合了

方式二:配置一个Mybatis插件,拦截ResultSetHandler,将返回结果进行处理。 这样的好处就是不用写自定义的处理器和在XxxMapper.xml中做配置,减少了工作

@Component
@Intercepts({
        @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
public class ResultSetInterceptor implements Interceptor {

    /**
     * json序列化规则
     */
    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;
    }
     * 将返回数据中心的JSONObject对象转换成正常的对象
     *
     * @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)));
                }
     * 判断是否跳过字段
     * @param value
     * @return
    private Boolean isNullValueField(Object value) {
        return null == value || "".equals(String.valueOf(value).trim())
                || (value instanceof Collection && ((Collection<?>) value).size() == 0);
     * 判断值是否包含JSONObject对象
    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;
}

到此这篇关于MySQL读取JSON转换的文章就介绍到这了,更多相关MySQL读取JSON转换内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

MySQL 相关文章推荐
MySql新手入门的基本操作汇总
May 13 MySQL
mysq启动失败问题及场景分析
Jul 15 MySQL
Mysql中where与on的区别及何时使用详析
Aug 04 MySQL
MySQL分库分表详情
Sep 25 MySQL
mysql sum(if())和count(if())的用法说明
Jan 18 MySQL
彻底解决MySQL使用中文乱码的方法
Jan 22 MySQL
关于k8s环境部署mysql主从的问题
Mar 13 MySQL
MySQL慢查询优化解决问题
Mar 17 MySQL
详细聊一聊mysql的树形结构存储以及查询
Apr 05 MySQL
mysql如何查询连续记录
May 11 MySQL
mysql中关键词exists的用法实例详解
Jun 10 MySQL
MySQL分布式恢复进阶
Jul 23 MySQL
分享MySQL常用 内核 Debug 几种常见方法
Mar 17 #MySQL
MySQL如何快速创建800w条测试数据表
Mar 17 #MySQL
利用JuiceFS使MySQL 备份验证性能提升 10 倍
MySQL 分区表中分区键为什么必须是主键的一部分
MySQL优化及索引解析
一条 SQL 语句执行过程
Mysql事务索引知识汇总
Mar 17 #MySQL
You might like
php中使用session防止用户非法登录后台的方法
2015/01/27 PHP
php 获取文件行数的方法总结
2016/10/11 PHP
浅谈php中curl、fsockopen的应用
2016/12/10 PHP
Extjs 3.3切换tab隐藏相应工具栏出现空白解决
2013/04/02 Javascript
用原生JavaScript实现jQuery的$.getJSON的解决方法
2013/05/03 Javascript
Jquery实现控件的隐藏和显示实例
2014/02/08 Javascript
javascript中apply和call方法的作用及区别说明
2014/02/14 Javascript
angularjs表格分页功能详解
2016/01/21 Javascript
JavaScript数据推送Comet技术详解
2016/04/07 Javascript
JavaScript中Array对象用法实例总结
2016/11/29 Javascript
微信小程序小组件 基于Canvas实现直播点赞气泡效果
2020/05/29 Javascript
angular-cli修改端口号【angular2】
2017/04/19 Javascript
详解vue-cli + webpack 多页面实例应用
2017/04/25 Javascript
利用webstrom调试Vue.js单页面程序的方法教程
2017/06/06 Javascript
ES6新特性:使用export和import实现模块化详解
2017/07/31 Javascript
layer.open关闭父窗口 以及调用父页面的方法
2018/08/17 Javascript
Vue加载组件、动态加载组件的几种方式
2018/08/31 Javascript
vue2.0中set添加属性后视图不能更新的解决办法
2019/02/22 Javascript
Vue 处理表单input单行文本框的实例代码
2019/05/09 Javascript
详解JavaScript作用域 闭包
2020/07/29 Javascript
vue-quill-editor插入图片路径太长问题解决方法
2021/01/08 Vue.js
分享Pycharm中一些不为人知的技巧
2018/04/03 Python
基于Python 装饰器装饰类中的方法实例
2018/04/21 Python
对pandas中to_dict的用法详解
2018/06/05 Python
Python中Numpy包的安装与使用方法简明教程
2018/07/03 Python
Python中字典与恒等运算符的用法分析
2019/08/22 Python
python的命名规则知识点总结
2019/10/04 Python
python自动结束mysql慢查询会话的实例代码
2019/10/27 Python
Python爬虫:Request Payload和Form Data的简单区别说明
2020/04/30 Python
Python下使用Trackbar实现绘图板
2020/10/27 Python
python基于爬虫+django,打造个性化API接口
2021/01/21 Python
纯CSS3代码实现switch滑动开关按钮效果
2016/08/30 HTML / CSS
阿联酋航空官方网站:Emirates
2017/10/17 全球购物
美国最大的香水出口:FragranceX.com
2017/11/04 全球购物
Dr. Martens马汀博士澳大利亚官网:马丁靴鼻祖
2019/07/02 全球购物
使用Mysql计算地址的经纬度距离和实时位置信息
2022/04/29 MySQL