当前位置:首页 > 技术分析 > 正文内容

MySQL实战——JSON数据类型_mysql jsonb类型

ruisui883个月前 (02-08)技术分析10

MySQL JSON类型简介

JavaScript Object Notation(JSON)是一种轻量级的、基于文本的,独立于语言的数据交换格式。它源自ECMAScript编程语言标准。

对于MySQL数据库,我们往往是将它作为一种关系型数据库,存放关系型数据库二维表。其实,从MySQL 5.7.8开始,MySQL已支持JSON数据类型,能够高效访问JSON文档中的数据。可以说是向着NoSQL存储功能迈出了一步。

MySQL 8 大幅改进了对 JSON 的支持,为 schema-less 模式的 JSON 文档提供了多文档事务支持和完整的 ACID 合规性。还添加了基于路径查询参数从 JSON 字段中抽取数据的JSON_EXTRACT()函数,以及用于将数据分别组合到 JSON 数组和对象中的 JSON_ARRAYAGG() 和 JSON_OBJECTAGG()聚合函数。

MySQL数据库原本可以将JSON格式的字符串当做String类型存储,但与之相比,JSON数据类型有以下优势:

(1)自动验证存储在JSON列中的JSON文档。无效的文档会产生错误。

(2)优化了存储格式。存储在JSON类型中的JSON文档被转换为允许对文档元素进行快速读取访问的内部格式。当读取以这种二进制格式存储的JSON值时,不需要从文本内容中解析该值,而能够直接通过键或数组索引查找子对象或嵌套值。

存储JSON文档所需的空间与LONGBLOB或LONGTEXT大致相同;MySQL使用utf8mb4字符集和utf8mb4_bin排序规则处理JSON类型的数据,因为utf8mb4_bin是二进制排序规则,所以JSON值是区分大小写的。

下面介绍JSON类型数据的创建、查询、修改以及相关内置函数。


创建

首先创建一个带有JSON类型字段的表,在一个表中,基本数据类型和JSON类型是可以共存的。示例为了简单起见,创建一个只包含JSON类型字段的表,如下:

create table sys_doc (doc json);

有两种方法将JSON数据存入该表。

  • 第一种方法,使用MySQL JSON_OBJECT()函数,这种方式下,若JSON值原本存在双引号,需要使用反斜杠对每个引号字符进行转义,例如,将如下这个键值对作为JSON数据存入表中:

mascot: The MySQL mascot is a dolphin named "Sakila".

INSERT语句为:

//JSON_OBJECT()函数构造JSON数据对象
//JSON数据内容中原本的引号需要用反斜杠转义
INSERT INTO sys_doc VALUES (JSON_OBJECT("mascot", "Our mascot is a dolphin named \"Sakila\"."));
  • 第二种方法,将JSON字符串作为参数传入INSERT语句,这种情况下,需要使用双反斜杠转义JSON值中原本存在的双引号,如下所示:
//直接将JSON字符串存入JSON类型
//使用双反斜杠可以防止MySQL执行转义处理,而是将字符串文本传递给存储引擎进行处理。
INSERT INTO sys_doc VALUES ('{"mascot": "Our mascot is a dolphin named \\"Sakila\\"."}');

通过执行SELECT,可以看到查询出的JSON列值中存在反斜杠,如下所示:

mysql> SELECT doc FROM sys_doc;
+---------------------------------------------------------+
| doc |
+---------------------------------------------------------+
| {"mascot": "Our mascot is a dolphin named \"Sakila\"."} |
+---------------------------------------------------------+

若要查找这个键值对对应的值,可以使用列路径操作符->,如下:

select doc->"$.mascot" from sys_doc;

查询结果:

"Our mascot is a dolphin named \"Sakila\"."

这个查询结果保留了反斜杠以及值起始位置的引号。要想只显示所需的值,而不包括起始位置引号和转义符,可以使用内联路径运算符->>,如下所示:

select doc->>"$.mascot" from sys_doc;

查询结果:

Our mascot is a dolphin named "Sakila".


查询

将下面这个JSON对象存入上文所建数据库表sys_doc,并以这个JSON对象展示相关JSON函数使用(该示例JSON对象表示了一个学生的高考成绩记录,包括姓名、年龄、总分、语文数学英语以及理综各科分数):

{
    "name":"王小虎",
    "age":17,
    "totalScore":582,
    "gender":"男",
    "chinese":120,
    "math":105,
    "english":118,
    "science":[
        88,
        85,
        66
    ]
}

存入以上JSON数据的INSERT语句为:

//JSON_OBJECT()函数创建JSON数据对象
INSERT INTO sys_doc VALUES (JSON_OBJECT('name', '王小虎', 'age', 17, 'totalScore', 582, 'gender', '男', 'chinese', 120, 'math', 105, 'english', 118, 'science', JSON_ARRAY(88, 85, 66)));


  • 查询“王小虎”同学的总分:
select JSON_EXTRACT(doc, "$.totalScore") from sys_doc WHERE JSON_EXTRACT(doc, "$.name") = '王小虎';


  • 查询“王小虎”同学的物理分数(假设"science":[88,85,66]分别表示理科综合中的物理、化学、生物各科的分数):
select JSON_EXTRACT(doc, "$.science[0]") from sys_doc WHERE JSON_EXTRACT(doc, "$.name") = '王小虎';

可以看到,访问数组元素的位置索引是以0开头的整数。


  • 查询“王小虎”同学的理综各科分数,以下三种方式都实现了相同的效果:
//数组元素索引与to关键字配合使用
select JSON_EXTRACT(doc, "$.science[0 to 2]") from sys_doc WHERE JSON_EXTRACT(doc, "$.name") = '王小虎';
//数组元素索引last关键字
select JSON_EXTRACT(doc, "$.science[last-2 to last]") from sys_doc WHERE JSON_EXTRACT(doc, "$.name") = '王小虎';
//表示全部数组元素的通配符*
select JSON_EXTRACT(doc, "$.science[*]") from sys_doc WHERE JSON_EXTRACT(doc, "$.name") = '王小虎';
  • 除了JSON_EXTRACT()函数,还可以用JSON_VALUE()函数,如下:
//JSON_VALUE()函数查询某个字段的值
select JSON_VALUE(doc, "$.science") FROM sys_doc WHERE JSON_VALUE(doc, "$.name") = '王小虎';


  • 查询出JSON文档中所有的KEY值:
//JSON_KEYS()函数列出JSON中所有key
select JSON_KEYS(doc) from sys_doc WHERE JSON_EXTRACT(doc, "$.name") = '王小虎';


  • 查询出JSON文档中所有的VALUE值:
//通配符查出JSON中所有value
select JSON_EXTRACT(doc, "$.*") from sys_doc WHERE JSON_EXTRACT(doc, "$.name") = '王小虎';

这些JSON相关的函数中,$表示正在操作的文档。下文还将展示更多范例。


修改

  • JSON_REPLACE()函数,将“王小虎”的年龄(age)改为20,“生物”分数修改为100:
//JSON_REPLACE()函数
update sys_doc set doc = JSON_REPLACE(doc, '$.age', 20, '$.science[last]', 100) WHERE JSON_EXTRACT(doc, "$.name") = '王小虎';
  • JSON_SET()函数,将年龄(age)改为21,“生物”分数修改为99
//JSON_SET()函数
update sys_doc set doc = JSON_SET(doc, '$.age', 21, '$.science[last]', 99) WHERE JSON_EXTRACT(doc, "$.name") = '王小虎';

此外,JSON_INSERT()函数也可以实现修改功能,他们三者的区别是函数处理文档中现有值和不存在值的方式不同。具体如下:

  1. JSON_SET()将替换现有路径的值,并为不存在的路径添加值。
  2. JSON_INSERT()添加新值,但不替换现有值。
  3. JSON_REPLACE()替换现有值并忽略新值。


删除

JSON_REMOVE()实现对JSON文档内容删除,参数为一个或多个指定要从文档中删除的值的路径。

  • 删除“王小虎”的年龄(age)、生物科目分数,如下:
//JSON_REMOVE()函数
update sys_doc set doc = JSON_REMOVE(doc, '$.age', '$.science[last]') WHERE JSON_EXTRACT(doc, "$.name") = '王小虎';

删除后的文档如下,没有了“age”字段以及“science”字段中的最后一个分数:

{
    "math": 105,
    "name": "王小虎",
    "gender": "男",
    "chinese": 120,
    "english": 118,
    "science": [
        88,
        85
    ],
    "totalScore": 582
}  


格式化

JSON_PRETTY()以可读格式打印JSON文档,例如:

select JSON_PRETTY('{"name":{"CN":"张三", "EN":"zhangsan"},"science":[120,98,90]}');

将会输入下面格式化的JSON文档:

{
    "name": {
        "CN": "张三",
        "EN": "zhangsan"
    },
    "science": [
        120,
        98,
        90
    ]
}

扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/1788.html

标签: json_extract
分享给朋友:

“MySQL实战——JSON数据类型_mysql jsonb类型” 的相关文章

Excel VBA 主界面/一步一步带你设计【收费管理系统】02

本文于2023年5月14日首发于本人同名公众号,更多文章案例请关注微信公众号:Excel活学活用!☆本期内容概要☆用户窗体设置:主界面、主页设计上期我们分享了EXCEL读取ACCESS数据库表,实现系统登录的功能【Excel VBA 访问带密码保护的Access数据库/用户窗体设置/EXCEL用户+...

手把手教你Vue之父子组件间通信实践讲解【props、$ref 、$emit】

组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用。那么组件间如何通信,也就成为了vue中重点知识了。这篇文章将会通过props、$ref和 $emit 这几个知识点,来讲解如何实现父子组件间通信。转载链接:https://www.jia...

2024前端面试真题之—VUE篇

添加图片注释,不超过 140 字(可选)1.vue的生命周期有哪些及每个生命周期做了什么? beforeCreate是new Vue()之后触发的第一个钩子,在当前阶段data、methods、computed以及watch上的数据和方法都不能被访问。 created在实例创建完成后发生,当前阶段已...

快速上手React

web前端三大主流框架1、Angular大家眼里比较牛的框架,甚至有人说三大框架中只有它能称得上一个完整的框架,因为它包含的东西比较完善,包含模板,数据双向绑定,路由,模块化,服务,过滤器,依赖注入等所有功能。对于刚开始学习使用框架的小伙伴们,可以推荐这个框架,学会之后简直能颠覆之前你对前端开发的认...

react hooks自定义组件居然能这样做

前言  这里写一下如何封装可复用组件。首先技术栈 react hooks + props-type + jsx封装纯函数组件。类组件和typeScript在这不做讨论,大家别白跑一趟。接下来会说一下封装可复用组件的思路,比如一个新手应该怎么去封装,都需要有哪些东西。  然后说一些复杂组件需要的功能,...

vue中组件之间的通信方式

** 1.1 父子组件**a. 父向子传数据: 第1种: 父通过属性传值,子组件通过props接收数据(注:props传过来的数据是单向的,不可以进行修改)第2种:子组件可以通过$parent来获取父组件里的数据和调用父组件的方法(注:数据是双向的,还要注意如用了UI组件并且在该UI组件里重新定义一...