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之高可用集群部署及故障切换实现
Apr 22 MySQL
MySQL 查询速度慢的原因
May 25 MySQL
为什么MySQL选择Repeatable Read作为默认隔离级别
Jul 26 MySQL
Mysql实现简易版搜索引擎的示例代码
Aug 30 MySQL
浅谈MySQL表空间回收的正确姿势
Oct 05 MySQL
MySQL 服务和数据库管理
Nov 11 MySQL
MySQL分区以及建索引的方法总结
Apr 13 MySQL
MySQL时区造成时差问题
Apr 13 MySQL
在MySQL中你成功的避开了所有索引
Apr 20 MySQL
MySQL 执行数据库更新update操作的时候数据库卡死了
May 02 MySQL
MySQL深分页问题解决思路
Dec 24 MySQL
MySQL中的 inner join 和 left join的区别解析(小结果集驱动大结果集)
May 08 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的错误信息
2006/10/09 PHP
PHP nl2br函数 将换行字符转成 &amp;lt;br&amp;gt;
2009/08/21 PHP
详解PHP中instanceof关键字及instanceof关键字有什么作用
2015/11/05 PHP
PHP cookie,session的使用与用户自动登录功能实现方法分析
2019/06/05 PHP
用PHP做了一个领取优惠券活动的示例代码
2019/07/05 PHP
php判断目录存在的简单方法
2019/09/26 PHP
php设计模式之组合模式实例详解【星际争霸游戏案例】
2020/03/27 PHP
TP5框架实现的数据库备份功能示例
2020/04/05 PHP
javascript 装载iframe子页面,自适应高度
2009/03/20 Javascript
DIV+CSS+JS不间断横向滚动实现代码
2013/03/19 Javascript
$.each与$().each的区别示例介绍
2014/03/20 Javascript
jQuery中对未来的元素绑定事件用bind、live or on
2014/04/17 Javascript
jQuery动态创建html元素的常用方法汇总
2014/09/05 Javascript
jquery Validation表单验证使用详解
2020/09/12 Javascript
JavaScript提高网站性能优化的建议(二)
2016/07/24 Javascript
每个程序员都需要学习 JavaScript 的7个理由小结
2016/09/03 Javascript
原生js实现节日时间倒计时功能
2017/01/18 Javascript
详解webpack+es6+angular1.x项目构建
2017/05/02 Javascript
React.js绑定this的5种方法(小结)
2018/06/05 Javascript
在Vue中使用axios请求拦截的实现方法
2018/10/25 Javascript
微信小程序地图绘制线段并且测量(实例代码)
2020/01/02 Javascript
[02:07]TI9显影之尘系列 - Vici Gaming
2019/08/20 DOTA
python学生信息管理系统(完整版)
2020/04/05 Python
python消费kafka数据批量插入到es的方法
2018/12/27 Python
pyqt5 键盘监听按下enter 就登陆的实例
2019/06/25 Python
Python实现简单的列表冒泡排序和反转列表操作示例
2019/07/10 Python
django 微信网页授权登陆的实现
2019/07/30 Python
Python扫描端口的实现
2021/01/25 Python
定制别致的瑜伽垫:Sugarmat
2019/06/21 全球购物
优秀班干部事迹材料
2014/01/26 职场文书
2015年迎新晚会策划书
2015/07/16 职场文书
《百分数的认识》教学反思
2016/02/19 职场文书
python urllib库的使用详解
2021/04/13 Python
MySQL中utf8mb4排序规则示例
2021/08/02 MySQL
sass 常用备忘案例详解
2021/09/15 HTML / CSS
CPU不支持Windows11系统怎么办
2021/11/21 数码科技