模式切换
Spring Boot 中如何处理存取 MySQL 中 JSON 类型的字段
已知在 MySQL 中有表 test_json_type,定义如下:
sql
-- 测试JsonType
drop table if exists test_json_type;
create table test_json_type
(
test_id bigint not null primary key comment 'testID',
ids json not null comment 'ids',
) engine innodb comment '测试JsonType表';
在 MyBatis-Plus 中,可以通过实现 TypeHandler 接口来创建自定义的类型处理器,用于处理 Java 类型和 JDBC 类型之间的转换。
为了处理 JSON 字符串和 Java 数组之间的转换,创建一个名为 JsonTypeHandler 的类,并实现 TypeHandler 接口,将 Java 中的字符串数组转换为 JSON 字符串存储到 MySQL 数据库中,以及将数据库中的 JSON 字符串转换回 Java 字符串数组。
首先,需要添加 Jackson 库到项目中,因为我们将使用它来序列化和反序列化 JSON:
xml
<!-- 添加Jackson依赖 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
然后,创建 JsonTypeHandler 类。使用 Jackson 库的 ObjectMapper 来执行 JSON 序列化和反序列化。setNonNullParameter 方法用于将 Java 数组转换为 JSON 字符串并设置到 PreparedStatement 中,而 getNullableResult 方法用于从 ResultSet 或 CallableStatement 中检索 JSON 字符串并转换回 Java 数组:
java
public class JsonTypeHandler<T> extends BaseTypeHandler<T> {
private static final ObjectMapper objectMapper = new ObjectMapper();
@Override
public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
try {
if (parameter instanceof String[]) {
String json = objectMapper.writeValueAsString((String[]) parameter);
ps.setString(i, json);
} else {
throw new IllegalArgumentException("Cannot convert type " + parameter.getClass().getName() + " to JSON");
}
} catch (JsonProcessingException e) {
throw new RuntimeException("Error converting to JSON", e);
}
}
@Override
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
String json = rs.getString(columnName);
if (json != null) {
try {
return (T) objectMapper.readValue(json, String[].class);
} catch (IOException e) {
throw new RuntimeException("Error converting JSON to type", e);
}
}
return null;
}
@Override
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String json = rs.getString(columnIndex);
if (json != null) {
try {
return (T) objectMapper.readValue(json, String[].class);
} catch (IOException e) {
throw new RuntimeException("Error converting JSON to type", e);
}
}
return null;
}
@Override
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String json = cs.getString(columnIndex);
if (json != null) {
try {
return (T) objectMapper.readValue(json, String[].class);
} catch (IOException e) {
throw new RuntimeException("Error converting JSON to type", e);
}
}
return null;
}
}
接下来,需要在 MyBatis 的映射文件或注解中指定使用这个自定义的类型处理器。如果使用 XML 映射文件,可以这样做:
xml
<resultMap id="productResultMap" type="com.example.Product">
<id column="id" property="id"/>
<result column="spec_ids" property="specIds" typeHandler="com.example.JsonTypeHandler"/>
<!-- 其他字段映射 -->
</resultMap>
如果使用注解,需在实体类开启映射 autoResultMap = true 并且在字段上使用 @TypeHandler 注解:
java
@Data
@EqualsAndHashCode(callSuper = true)
@TableName(value = "test_json_type", autoResultMap = true)
public class TestJsonType extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* testID
*/
@TableId(value = "test_id")
private Long testId;
/**
* ids
*/
@TableField(value = "ids", typeHandler = JsonTypeHandler.class)
private String[] ids;
}
然后就可以正常地存取 JSON 类型的字段了: