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 18 MySQL
MySql 8.0及对应驱动包匹配的注意点说明
Jun 23 MySQL
mysql优化之query_cache_limit参数说明
Jul 01 MySQL
MySQL系列之八 MySQL服务器变量
Jul 02 MySQL
MySQL修炼之联结与集合浅析
Oct 05 MySQL
Mysql外键约束的创建与删除的使用
Mar 03 MySQL
MySQL如何快速创建800w条测试数据表
Mar 17 MySQL
分享几个简单MySQL优化小妙招
Mar 31 MySQL
Windows下载并安装MySQL8.0.x 版本的完整教程
Apr 10 MySQL
Mysql排查分析慢sql之explain实战案例
Apr 19 MySQL
CentOS MySql8 远程连接实战
Apr 19 MySQL
前端传参数进行Mybatis调用mysql存储过程执行返回值详解
Aug 14 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得到mssql的存储过程的输出参数功能实现
2012/11/23 PHP
ThinkPHP模板替换与系统常量及应用实例教程
2014/08/22 PHP
PDO预处理语句PDOStatement对象使用总结
2014/11/20 PHP
php利用scws实现mysql全文搜索功能的方法
2014/12/25 PHP
php 静态属性和静态方法区别详解
2017/04/09 PHP
如何实现JS函数的重载
2006/09/22 Javascript
JS多物体 任意值 链式 缓冲运动
2012/08/10 Javascript
JQuery实现用户名无刷新验证的小例子
2013/03/22 Javascript
jquery 选取方法都有哪些
2014/05/18 Javascript
浅谈EasyUI中Treegrid节点的删除
2015/03/01 Javascript
jQuery的基本概念与高级编程
2015/05/14 Javascript
JavaScript日期选择功能示例
2017/01/16 Javascript
js实现自动图片轮播代码
2017/03/22 Javascript
微信小程序 自动登陆PHP源码实例(源码下载)
2017/05/08 Javascript
纯JS实现简单的日历
2017/06/26 Javascript
js匿名函数使用&amp;传参(实例)
2017/09/08 Javascript
Javascript 严格模式use strict详解
2017/09/16 Javascript
js中document.write和document.writeln的区别
2018/03/11 Javascript
vue router的基本使用和配置教程
2018/11/05 Javascript
python生成器的使用方法
2013/11/21 Python
python实现2048小游戏
2015/03/30 Python
使用Python编写简单的端口扫描器的实例分享
2015/12/18 Python
微信跳一跳自动运行python脚本
2018/01/08 Python
python实现简易内存监控
2018/06/21 Python
Python爬虫beautifulsoup4常用的解析方法总结
2019/02/25 Python
使用python实现离散时间傅里叶变换的方法
2019/09/02 Python
Python高级特性——详解多维数组切片(Slice)
2019/11/26 Python
美国知名户外用品畅销中心:Sierra Trading Post
2016/07/19 全球购物
白酒市场开发计划书
2014/01/09 职场文书
党风廉政建设责任书
2014/04/14 职场文书
前台接待岗位职责范本
2015/04/03 职场文书
行政助理岗位职责范本
2015/04/11 职场文书
贷款工资证明范本
2015/06/12 职场文书
Java中常用解析工具jackson及fastjson的使用
2021/06/28 Java/Android
python 标准库原理与用法详解之os.path篇
2021/10/24 Python
【海涛教你打DOTA】剑圣第一人称视角解说
2022/04/01 DOTA