当前位置: 首页 > article >正文

mysql JSON字段使用

1.背景

Mysql5.7.8版本以后新增的功能,Mysql提供了一个原生的Json类型,Json值将不再以字符串的形式存储,而是采用一种允许快速读取文本元素(document elements)的内部二进制(internal binary)格式,并提供了不少内置函数,通过计算列,甚至还可以直接索引json中的数据。

2.数据库基本操作

1.表结构

新建表

CREATE TABLE `table_name` (  
   `id` INT UNSIGNED NOT NULL,
   `business_attr` JSON NOT NULL,
   PRIMARY KEY (`id`)
);

新增json类型字段

alter table table_name add column `business_attr` JSON NULL;

2.插入操作

在json数据列提供json格式的字符串即可

insert into table_name values(1,'{"attr_key1":"attr_value1","attr_key2":"attr_value2"}');

如果是字符串,可以通过cast函数转成json

insert into table_name values(1,CAST('{"attr_key1":"attr_value1","attr_key2":"attr_value2"}', as JSON));

3.更新操作

1.json_set更新json字段

update table_name set business_attr=json_set('{"num":1,"name":"abc"}','$.num',2,'$.age',16,'$.class.id',1) where id=1;
  • JSON_SET(json_doc, path, val[, path, val] ...)

  • path中$就代表整个doc,然后可以用javascript的方式指定对象属性或者数组下标等.

  • 值存在就修改,值不存在就设置,路径不存在将直接被忽略。

2.json_merge_patch更新json字段

update table_name set business_attr=JSON_MERGE_PATCH(IFNULL(business_attr,json_object()),JSON_OBJECT('attr_key1',CAST('attr_value1' as JSON))) where id=1;

MySQL JSON_MERGE_PATCH() 函数返回一个由参数指定的多个 JSON 文档合并后的 JSON 文档。JSON_MERGE_PATCH() 执行的是替换合并,即在相同键值时,只保留后面的值。

3.json_insert插入json字段

  • JSON_INSERT(json_doc, path, val[, path, val] ...)

  • 如果不存在对应属性则插入,否则不做任何变动

4.删除操作

json_remove方法删除某个属性

update table_name set business_attr=JSON_REMOVE(business_attr,'$.attr_key1') where id=1;
  • JSON_REMOVE(json_doc, path[, path] ...)

  • 如果存在则删除对应属性,否则不做任何变动

5.查询操作

1.使用json_extract函数查询,获得doc中某个或多个节点的值。

JSON_EXTRACT(json_doc, path[, path] ...)

SELECT JSON_EXTRACT(business_attr, '$.attr_key1') where id=1;

2.使用 字段->'$.json属性'进行查询条件

mysql5.7.9开始增加了一种简写方式:column->path

SELECT business_attr->'$.attr_key1' where id=1;

JSON相关函数参考

https://www.sjkjc.com/mysql-ref/json-functions/

3.结合Mybatis使用

TypeHandler 是 Mybatis 中用来处理 Java 类型与数据库类型之间的映射的一个接口。当你需要自定义数据类型的映射规则时,就需要实现这个接口。

例如,需要将新增的JSON字段business_attr映射成Map类型,就需要实现一个MapTypeHandler,用来处理Java中Map和数据JSON字段类型的转换。

[注意]  在自定义类型转换逻辑的情况下,需要显式的配置启用autoResultMap,从而自动映射sql查询结果到相应的实体对象。

1.Java实体类配置

如前所述,需要自定义一个MapTypeHandler,并在JSON类型字段上配置,同时启用autoResultMap。

@TableName(value = "table_name", autoResultMap = true)
public class TableName {
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    
    @TableField(typeHandler = MapTypeHandler.class)
    private Map<String, Object> businessAttr;
}

2.增删改操作

为了操作方便,这里统一都使用JSON_MERGE_PATCH作为字段插入和更新的方法,JSON_REMOVE作为字段删除的方法,可根据实际需要调整。

//新增和修改
public Boolean updateBusinessAttr(AttrDTO dto){
    String setSql = " business_attr=JSON_MERGE_PATCH(IFNULL(business_attr,json_object()),JSON_OBJECT('%s',CAST('%s' as JSON)))";
    LambdaUpdateWrapper<TableName> updateWrapper = new LambdaUpdateWrapper<>();
    updateWrapper.eq(TableName::getId, dto.getId());
    updateWrapper.setSql(String.format(setSql, dto.getAttrKey(), UniMybatisJacksonUtil.toJson(dto.getValue())));
    this.update(updateWrapper);
    return true;
}
​
//删除
public Boolean deleteBusinessAttr(AttrDTO dto) {
    LambdaUpdateWrapper<TableName> updateWrapper = new LambdaUpdateWrapper<>();
    updateWrapper.eq(TableName::getId, dto.getId());
    String setSql = " business_attr=JSON_REMOVE(business_attr,'$.%s')";
    updateWrapper.setSql(String.format(setSql, dto.getAttrKey()));
    this.update(updateWrapper);
    return true;
}

3.查询操作

直接在mapper.xml文件里编写对应字段查询条件。

<!-- 查询attrKey=attrValue的记录 -->
<if test="pageQuery.attrs != null and pageQuery.attrs.size() > 0">
    and
    <foreach collection="pageQuery.attrs" index="attrKey" item="attrValue" open="("
             separator="and" close=")">
        table_name.business_attr->'$.${attrKey}' = #{attrValue}
    </foreach>
</if>

对查询结果进行操作,直接将数据库查询结果强转成入库时的格式即可。

//入库时kvMap值格式是Map<String, String>,查询结果可以直接强转
Map<String, String> kvMap = (Map<String, Object>) tableName.getBusinessAttr().get("kvMap");

4.json特殊字符处理

如果json字符串中含有转义符或者mysql不支持的字符,会导致入库失败,因此需要自定义JSON字符串处理类UniMybatisJacksonUtil对特殊字符处理一下。

  • typeHandler在入库前,重写setNonNullParameter方法:

public void setNonNullParameter(PreparedStatement ps, int i, Map<K, V> parameter, JdbcType jdbcType) throws SQLException {
    ps.setString(i, this.toJson(parameter));
}
​
private String toJson(Map<K, V> params) {
    try {
        return UniMybatisJacksonUtil.toJson(params);
    } catch (Exception var3) {
        var3.printStackTrace();
        return "{}";
    }
}
  • 单独更新字段时,处理待更新对象

updateWrapper.setSql(String.format(setSql, dto.getAttrKey(), UniMybatisJacksonUtil.toJson(dto.getValue())));

[注意]  Java实体类中map的value是一个对象,注意在入库前不要把value序列化成String,否则会导致入库的值带有转义符;如果有逻辑要求必须序列化,在入库之前再额外执行一次反序列化成对象。

if (JSONUtil.isTypeJSON(updateAttrs.get(key))) {
    //如果value已经是JSON格式,反序列化成对象
    attrDTO.setValue(JSON.parse(updateAttrs.get(key)));
}

http://www.kler.cn/a/379381.html

相关文章:

  • 【数据分享】1901-2023年我国省市县镇四级的逐年最高气温数据(免费获取/Shp/Excel格式)
  • Rust 力扣 - 643. 子数组最大平均数 I
  • 数据结构 —— AVL树
  • STM32MP135 linux6.1.82版本移植RTL8723DS WIFI驱动
  • Mac 配置SourceTree集成云效
  • Django响应
  • Gitlab-runner running on Kubernetes - hostAliases
  • 深度学习笔记7-最小二乘法
  • 享元模式-实现大颗粒度对象缓存机制
  • Cesium移动3D模型位置
  • docker desktop使用ubuntu18.04带图形化+运行qemu
  • 划界与分类的艺术:支持向量机(SVM)的深度解析
  • metasploit/modules/evasion 有哪些模块,以及具体使用案例
  • WebService详解
  • 服务器数据恢复—SAN环境中LUN映射错误导致文件系统一致性出错的数据恢复案例
  • 【neo4j】 图数据库neo4j cypher单一语句 optional 可选操作的技巧
  • “代码世界的必修课:Git完整指南“(3)
  • JVM基本结构和垃圾回收机制
  • 小白从零开始学c++之继承对象的内存空间
  • nodejs入门教程8:nodejs EventEmitter
  • 《Java 实现希尔排序:原理剖析与代码详解》
  • 三维测量与建模笔记 - 2.2 射影几何
  • Hive数据库操作语法
  • Java-I/O框架10:File类、文件操作
  • docker部署Flask+Vue3项目
  • Leetcode328奇偶链表,Leetcode21合并两个有序链表,Leetcode206反转链表 三者综合题