根据你的要求,以下是“MybatisPlus保存、读取MySQL中的json字段失败问题及解决”的完整攻略。
问题描述
在使用MybatisPlus操作MySQL数据库时,如果遇到要保存或读取包含JSON类型字段的表时,可能会出现保存或读取失败的情况。具体表现为:保存后JSON字段丢失或读取时解析失败。
问题分析
出现这种情况的原因主要有两个:
-
MySQL版本问题。MybatisPlus默认使用MySQL 8以下版本的JSON类型字段所对应的VARCHAR类型进行保存和读取,而MySQL 8以上版本使用的是JSON类型字段。如果使用MySQL 8以上版本,就需要对MybatisPlus进行配置。
-
数据库驱动问题。如果使用的是老版本的MySQL的驱动(如mysql-connector-java-5.1.20),就会出现JSON字段无法保存或读取的问题。需要使用较新的驱动版本(如mysql-connector-java-5.1.46)。
解决方案
方案一:修改MySQL连接驱动版本
- 在Maven中使用以下依赖:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
- 修改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技术站