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 MVCC机制原理详解
Apr 20 MySQL
MySQL 覆盖索引的优点
May 19 MySQL
.Net Core导入千万级数据至Mysql的步骤
May 24 MySQL
简单了解 MySQL 中相关的锁
May 25 MySQL
MySQL 查询速度慢的原因
May 25 MySQL
如何使用分区处理MySQL的亿级数据优化
Jun 18 MySQL
MySQL 外键约束和表关系相关总结
Jun 20 MySQL
sql注入教程之类型以及提交注入
Aug 02 MySQL
MySQL 1130异常,无法远程登录解决方案详解
Aug 23 MySQL
一次SQL如何查重及去重的实战记录
Mar 13 MySQL
MySQL中rank() over、dense_rank() over、row_number() over用法介绍
Mar 23 MySQL
Mysql开启外网访问
May 15 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编程之高级技巧——利用Mysql函数
2006/10/09 PHP
探讨:如何使用PHP实现计算两个日期间隔的年、月、周、日数
2013/06/13 PHP
php计算当前程序执行时间示例
2014/04/24 PHP
ThinkPHP3.2框架使用addAll()批量插入数据的方法
2017/03/16 PHP
JS正则中的RegExp对象对象
2012/11/07 Javascript
基于jQuery实现下拉收缩(展开与折叠)特效
2012/12/25 Javascript
简单的两种Extjs formpanel加载数据的方式
2013/11/09 Javascript
javascript 数字格式化输出的实现代码
2013/12/10 Javascript
Angularjs 基础入门
2014/12/26 Javascript
javascript实现简单的分页特效
2015/08/12 Javascript
javascript定义类和类的实现实例详解
2015/12/01 Javascript
jquery实现全选和全不选功能效果的实现代码【推荐】
2016/05/05 Javascript
输入法的回车与消息发送快捷键回车的冲突解决方法
2016/08/09 Javascript
jQuery多个版本和其他js库冲突的解决方法
2016/08/11 Javascript
利用jquery实现下拉框的禁用与启用
2016/12/07 Javascript
JavaScript适配器模式详解
2017/10/19 Javascript
解决JSON.stringify()自动将中文转译成unicode的问题
2018/01/05 Javascript
JavaScript实用代码小技巧
2018/08/23 Javascript
解决vue.js this.$router.push无效的问题
2018/09/03 Javascript
element ui 表格动态列显示空白bug 修复方法
2018/09/04 Javascript
在vue中使用v-bind:class的选项卡方法
2018/09/27 Javascript
jQuery实现数字自动增加或者减少的动画效果示例
2018/12/11 jQuery
图文详解vue框架安装步骤
2019/02/12 Javascript
JS扁平化输出数组的2种方法解析
2019/09/17 Javascript
JavaScript Tab菜单实现过程解析
2020/05/13 Javascript
详细分析vue表单数据的绑定
2020/07/20 Javascript
JS pushlet XMLAdapter适配器用法案例解析
2020/10/16 Javascript
selenium+python 对输入框的输入处理方法
2018/10/11 Python
python操作小程序云数据库实现简单的增删改查功能
2019/06/06 Python
python设置环境变量的作用和实例
2019/07/09 Python
基于python实现破解滑动验证码过程解析
2020/05/28 Python
Python3爬虫发送请求的知识点实例
2020/07/30 Python
Python3.9.1中使用split()的处理方法(推荐)
2021/02/07 Python
广告设计专业自荐信范文
2013/11/14 职场文书
班组建设经验交流材料
2014/05/12 职场文书
打架检讨书范文
2015/01/27 职场文书