MybatisPlus保存、读取MySQL中的json字段失败问题及解决

yizhihongxing

根据你的要求,以下是“MybatisPlus保存、读取MySQL中的json字段失败问题及解决”的完整攻略。

问题描述

在使用MybatisPlus操作MySQL数据库时,如果遇到要保存或读取包含JSON类型字段的表时,可能会出现保存或读取失败的情况。具体表现为:保存后JSON字段丢失或读取时解析失败。

问题分析

出现这种情况的原因主要有两个:

  1. MySQL版本问题。MybatisPlus默认使用MySQL 8以下版本的JSON类型字段所对应的VARCHAR类型进行保存和读取,而MySQL 8以上版本使用的是JSON类型字段。如果使用MySQL 8以上版本,就需要对MybatisPlus进行配置。

  2. 数据库驱动问题。如果使用的是老版本的MySQL的驱动(如mysql-connector-java-5.1.20),就会出现JSON字段无法保存或读取的问题。需要使用较新的驱动版本(如mysql-connector-java-5.1.46)。

解决方案

方案一:修改MySQL连接驱动版本

  1. 在Maven中使用以下依赖:
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.46</version>
</dependency>
  1. 修改MybatisPlus的全局配置,指明使用MySQL的JSON类型,如下所示:
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return configuration -> configuration.setUseDeprecatedExecutor(false);
    }

    @Bean
    public ISqlInjector sqlInjector() {
        return new LogicSqlInjector();
    }

    @Bean
    public ConfigurationCustomizer jsonCustomizer() {
        return configuration -> {
            configuration.getTypeHandlerRegistry()
                .register(JSONObject.class, new JSONTypeHandler());
            configuration.getTypeHandlerRegistry()
                .register(JSONArray.class, new JSONTypeHandler());
            configuration.getTypeHandlerRegistry()
                .register(JSONObject.class.getName(), new JSONTypeHandler());
            configuration.getTypeHandlerRegistry()
                .register(JSONArray.class.getName(), new JSONTypeHandler());
        };
    }
}

方案二:使用VARCHAR类型保存JSON字段

虽然MySQL 8以上版本使用JSON类型来保存JSON字段是更加合理和优秀的方案,但是,如果想使用VARCHAR类型来保存JSON字段,也是可行的。这时,需要修改MybatisPlus的JSON序列化和反序列化类型。

public class VarcharJsonTypeHandler extends BaseTypeHandler<Object> {

    private static final ObjectMapper mapper = new ObjectMapper();

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
        if (parameter instanceof String) {
            ps.setString(i, (String) parameter);
        } else {
            try {
                ps.setString(i, mapper.writeValueAsString(parameter));
            } catch (JsonProcessingException e) {
                throw new SQLException(e);
            }
        }
    }

    @Override
    public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String value = rs.getString(columnName);
        if (value == null) {
            return null;
        }
        try {
            return mapper.readValue(value, Object.class);
        } catch (IOException e) {
            throw new SQLException(e);
        }
    }

    @Override
    public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String value = rs.getString(columnIndex);
        if (value == null) {
            return null;
        }
        try {
            return mapper.readValue(value, Object.class);
        } catch (IOException e) {
            throw new SQLException(e);
        }
    }

    @Override
    public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String value = cs.getString(columnIndex);
        if (value == null) {
            return null;
        }
        try {
            return mapper.readValue(value, Object.class);
        } catch (IOException e) {
            throw new SQLException(e);
        }
    }
}

然后,在MybatisPlus的全局配置中指定使用VARCHAR类型即可。

public class MybatisPlusConfig {
    @Bean
    public ConfigurationCustomizer jsonCustomizer() {
        return configuration -> {
            configuration.getTypeHandlerRegistry()
                    .register(JSONObject.class, new VarcharJsonTypeHandler());
            configuration.getTypeHandlerRegistry()
                    .register(JSONArray.class, new VarcharJsonTypeHandler());
            configuration.getTypeHandlerRegistry()
                    .register(JSONObject.class.getName(), new VarcharJsonTypeHandler());
            configuration.getTypeHandlerRegistry()
                    .register(JSONArray.class.getName(), new VarcharJsonTypeHandler());
        };
    }
}

示例说明

示例一

假设我们有一张用户表,其中有一个字段叫做“user_info”,用来保存用户的基本信息JSON字符串。以下是该表的建表语句:

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL COMMENT '用户ID',
  `user_info` json NOT NULL COMMENT '用户信息',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';

为了解决MybatisPlus在保存和读取MySQL JSON字段时的问题,我们在全局配置中加入JSONTypeHandler,如下所示(假设我们使用的是方案一):

public class MybatisPlusConfig {
    @Bean
    public ConfigurationCustomizer jsonCustomizer() {
        return configuration -> {
            configuration.getTypeHandlerRegistry()
                    .register(JSONObject.class, new JSONTypeHandler());
            configuration.getTypeHandlerRegistry()
                    .register(JSONArray.class, new JSONTypeHandler());
            configuration.getTypeHandlerRegistry()
                    .register(JSONObject.class.getName(), new JSONTypeHandler());
            configuration.getTypeHandlerRegistry()
                    .register(JSONArray.class.getName(), new JSONTypeHandler());
        };
    }
}

然后,我们在用户表的实体类中定义一个类型为JSONObject的属性user_info:

@Data
@EqualsAndHashCode(callSuper = false)
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    private JSONObject user_info;
}

这就表示我们可以将用户信息的JSON字符串保存到user_info字段中。使用MybatisPlus的插入方法可以很方便的插入数据:

User user = new User();
user.setUser_info(new JSONObject().fluentPut("name", "zhangsan").fluentPut("age", 20));
boolean success = user.insert();

插入完数据后,我们可以使用MybatisPlus的查询方法读取User表的数据:

List<User> userList = user.selectList(new QueryWrapper<>());
for (User user : userList) {
    System.out.println(user.getUser_info());
}

输出结果为:

{"name":"zhangsan","age":20}

示例二

假设我们使用的是方案二,使用VARCHAR类型保存JSON字段,我们需要在全局配置中加入VarcharJsonTypeHandler,如下所示:

public class MybatisPlusConfig {
    @Bean
    public ConfigurationCustomizer jsonCustomizer() {
        return configuration -> {
            configuration.getTypeHandlerRegistry()
                    .register(JSONObject.class, new VarcharJsonTypeHandler());
            configuration.getTypeHandlerRegistry()
                    .register(JSONArray.class, new VarcharJsonTypeHandler());
            configuration.getTypeHandlerRegistry()
                    .register(JSONObject.class.getName(), new VarcharJsonTypeHandler());
            configuration.getTypeHandlerRegistry()
                    .register(JSONArray.class.getName(), new VarcharJsonTypeHandler());
        };
    }
}

在用户表实体类的定义上也要有一些变化,user_info字段需要定义为String类型。

@Data
@EqualsAndHashCode(callSuper = false)
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    private String user_info;
}

然后,我们就可以通过MybatisPlus的插入方法向用户表中添加数据,如下所示:

User user = new User();
user.setUser_info("{\"name\": \"zhangsan\", \"age\": 20}");
boolean success = user.insert();

同样,我们也可以通过MybatisPlus的查询方法读取User表中的数据。

List<User> userList = user.selectList(new QueryWrapper<>());
for (User user : userList) {
    System.out.println(user.getUser_info());
}

输出结果为:

{"name": "zhangsan", "age": 20}

总结

无论我们是使用哪一种方案来解决在MybatisPlus中保存和读取MySQL JSON字段时出现的问题,最终的目的都是为了让MybatisPlus能够正确、有效的进行操作,最大限度的利用和发挥JSON字段所携带的信息。在使用时,需要针对具体的业务场景选择合适的方案,才能达到最好的效果。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:MybatisPlus保存、读取MySQL中的json字段失败问题及解决 - Python技术站

(0)
上一篇 2023年5月18日
下一篇 2023年5月18日

相关文章

  • MySQL基本架构与锁的知识点有哪些

    本篇内容主要讲解“MySQL基本架构与锁的知识点有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“MySQL基本架构与锁的知识点有哪些”吧! MySql架构 SQL Layer Connection Pool : 连接池,用于接收连接请求和管理连接。 ManagementService&Utilitie…

    2023年4月8日
    00
  • linux下备份MYSQL数据库的方法

    备份MYSQL数据库是服务器管理中常用的任务之一。下面简要介绍linux环境下备份MYSQL数据库的两种方法: 方法一:使用mysqldump命令备份数据库 登录MYSQL数据库 mysql -u root -p 进入MYSQL后,使用以下命令备份数据库 mysqldump -u root -p 数据库名 > 备份文件名.sql 备份成功后,可以使用以…

    database 2023年5月22日
    00
  • springboot 启动时初始化数据库的步骤

    为了在Spring Boot启动时初始化数据库,需要遵循以下步骤: 1.创建一个SQL文件 首先,我们需要创建一个SQL文件,里面包含我们要初始化的数据。文件可以是任何带有SQL语句的文本文件。以下是文件的示例: INSERT INTO users (id, name, email, password) VALUES (1, ‘John Doe’, ‘joh…

    database 2023年5月22日
    00
  • mysql 显示SQL语句执行时间的代码

    要显示MySQL语句的执行时间,可以通过以下步骤实现: 打开MySQL客户端(如MySQL Workbench)并连接到目标数据库。 在客户端中执行以下语句: SET profiling = 1; 该命令会开启MySQL的性能分析工具,在后续的所有语句执行过程中,都会生成相应的性能分析数据。 执行需要分析的SQL语句: SELECT * FROM users…

    database 2023年5月22日
    00
  • MySQL 移动数据目录后启动失败问题解决

    针对“MySQL 移动数据目录后启动失败问题解决”,我们可以采取以下步骤来解决: 步骤一:备份数据目录 在移动数据目录之前,我们需要对原有数据目录进行备份,以避免数据丢失。可以通过以下命令来进行备份: tar czvf mysql_data.tar.gz /var/lib/mysql 其中,/var/lib/mysql 是原有数据目录的路径,可以根据实际情况…

    database 2023年5月18日
    00
  • MySQL给数据库表添加字段

    MySQL 给数据库表添加字段的方法: ALTER TABLE 语句 ALTER TABLE 语句可以在数据表中添加、修改或删除字段。 添加字段: 语法:ALTER TABLE table_name ADD column_name column_definition; 例: ALTER TABLE student ADD age INT(3); 在 stud…

    MySQL 2023年3月9日
    00
  • Mysql中key 、primary key 、unique key 与index区别

    key 是数据库的物理结构,它包含两层意义和作用, 一是约束(偏重于约束和规范数据库的结构完整性), 二是索引(辅助查询用的)。   https://www.cnblogs.com/zjfjava/p/6922494.html   CREATE TABLE `act_ru_execution` ( `ID_` varchar(64) COLLATE utf8…

    MySQL 2023年4月16日
    00
  • Redis 的 GEO 特性将在 Redis 3.2 版本释出

    Redis 的 GEO 特性将在 Redis 3.2 版本释出, 这个功能可以将用户给定的地理位置信息储存起来, 并对这些信息进行操作。 本文将对 Redis 的 GEO 特性进行介绍, 说明这个特性相关命令的用户, 并在最后说明如何使用这些命令去实现“查找附近的人”以及“摇一摇”这两个功能。   版本要求 因为 Redis 目前的稳定版本为 Redis 3…

    Redis 2023年4月11日
    00
合作推广
合作推广
分享本页
返回顶部