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 05 MySQL
MySQL数字类型自增的坑
May 07 MySQL
MySQL如何构建数据表索引
May 13 MySQL
修改MySQL的默认密码的四种小方法
May 26 MySQL
MySQL 百万级数据的4种查询优化方式
Jun 07 MySQL
mysql备份策略的实现(全量备份+增量备份)
Jul 07 MySQL
MySQL和Oracle批量插入SQL的通用写法示例
Nov 17 MySQL
Mysql存储过程、触发器、事件调度器使用入门指南
Jan 22 MySQL
MySQL的InnoDB存储引擎的数据页结构详解
Mar 03 MySQL
解决MySQL Varchar 类型尾部空格的问题
Apr 06 MySQL
解决Mysql报错 Table 'mysql.user' doesn't exist
May 06 MySQL
Mysql数据库事务的脏读幻读及不可重复读详解
May 30 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 命令行工具 shell_exec, exec, passthru, system详细使用介绍
2011/09/11 PHP
thinkphp 手机号和用户名同时登录
2017/01/20 PHP
xss文件页面内容读取(解决)
2010/11/28 Javascript
JavaScript性能陷阱小结(附实例说明)
2010/12/28 Javascript
固定表格行列(expression)在IE下适用
2013/07/25 Javascript
jQuery实现仿淘宝带有指示条的图片转动切换效果完整实例
2015/03/04 Javascript
浅谈被jQuery抛弃的函数及替代函数
2015/05/03 Javascript
实例详解Nodejs 保存 payload 发送过来的文件
2016/01/14 NodeJs
jQuery Mobile框架中的表单组件基础使用教程
2016/05/17 Javascript
深入理解在JS中通过四种设置事件处理程序的方法
2017/03/02 Javascript
JavaScript阻止表单提交方法(附代码)
2017/08/15 Javascript
jquery+css3实现熊猫tv导航代码分享
2018/02/12 jQuery
Node.js事件的正确使用方法
2019/04/05 Javascript
vue滚动固定顶部及修改样式的实例代码
2019/05/30 Javascript
Node.js实现批量下载图片简单操作示例
2020/01/18 Javascript
js实现时间日期校验
2020/05/26 Javascript
Vue实现计算器计算效果
2020/08/17 Javascript
Python基本语法经典教程
2016/03/11 Python
PyQt5每天必学之拖放事件
2020/08/27 Python
Django使用HttpResponse返回图片并显示的方法
2018/05/22 Python
Python3实现腾讯云OCR识别
2018/11/27 Python
python爬虫 基于requests模块发起ajax的get请求实现解析
2019/08/20 Python
python实现高斯(Gauss)迭代法的例子
2019/11/20 Python
Python爬虫解析网页的4种方式实例及原理解析
2019/12/30 Python
浅谈Python3多线程之间的执行顺序问题
2020/05/02 Python
深入了解NumPy 高级索引
2020/07/24 Python
django 获取字段最大值,最新的记录操作
2020/08/09 Python
使用HTML5做个画图板的方法介绍
2013/05/03 HTML / CSS
美国隐形眼镜销售网站:ContactsDirect
2017/10/28 全球购物
I.T中国官网:精选时尚设计师单品网购平台
2018/03/26 全球购物
幼儿园托班开学寄语
2014/01/18 职场文书
即将毕业大学生自荐信
2014/01/24 职场文书
寒假实习自荐信
2014/01/26 职场文书
小学生植树节活动总结
2014/07/04 职场文书
SQL 窗口函数实现高效分页查询的案例分析
2021/05/21 SQL Server
ajax请求前端跨域问题原因及解决方案
2021/10/16 Javascript