首页 > 科技周边 > IT业界 > 如何在MySQL数据库中使用JSON数据字段

如何在MySQL数据库中使用JSON数据字段

William Shakespeare
发布: 2025-02-08 08:49:11
原创
140 人浏览过

How to Use JSON Data Fields in MySQL Databases

本文探讨了MySQL 9.1中JSON实现的细节,延续了之前文章《SQL vs NoSQL: The Differences》中关于SQL和NoSQL数据库界限模糊的论点,两者都在互相借鉴特性。MySQL 5.7 InnoDB数据库和PostgreSQL 9.2 都直接支持在单个字段中存储JSON文档类型。

需要注意的是,任何数据库都能将JSON文档作为单个字符串blob存储。然而,MySQL和PostgreSQL支持将验证后的JSON数据存储为真正的键值对,而不是简单的字符串。

关键要点

  • MySQL 5.7 InnoDB数据库和PostgreSQL 9.2 直接支持JSON文档类型,但由于直接索引的限制,应谨慎使用。
  • JSON最适合存储稀疏数据、自定义属性、层次结构以及需要灵活性的情况。它不应替代经常查询或索引数据的规范化列。
  • MySQL提供各种函数来创建、验证、搜索和修改JSON对象。这些函数包括JSON_ARRAY()、JSON_OBJECT()、JSON_QUOTE()、JSON_TYPE()、JSON_VALID()、JSON_CONTAINS()、JSON_SEARCH(),以及用于使用路径表示法更新JSON文档的JSON_SET()和JSON_MERGE_PATCH()等函数。
  • MySQL 9.1支持对从JSON数据派生的生成列进行函数索引,从而能够高效地查询特定的JSON元素。
  • 虽然MySQL支持JSON,但它仍然是一个关系型数据库。过度使用JSON可能会抵消SQL的优势。

在MySQL JSON列中存储JSON文档并不意味着你应该这样做

规范化是一种用于优化数据库结构的技术。第一范式(1NF)规则规定每一列都应该保存单个值——而存储多值JSON文档显然违反了这一规则。

如果你的数据有明确的关系型数据需求,请使用合适的单值字段。JSON应该作为最后手段谨慎使用。JSON值字段不能直接索引,因此避免在经常更新或搜索的列上使用它们。

对从JSON数据派生的生成列进行函数索引,允许你索引JSON对象的某些部分,从而提高查询性能。

也就是说,对于稀疏数据或自定义属性,JSON有一些很好的用例。

创建带有JSON数据类型列的表

考虑一家销售书籍的商店。所有书籍都有ID、ISBN、标题、出版商、页数和其他明确的关系型数据。

现在,如果你想为每本书添加任意数量的类别标签。你可以在SQL中使用以下方法实现:

  1. 一个标签表,存储每个标签名称及其唯一的ID;
  2. 一个标签映射表,包含许多到许多的记录,将书籍ID映射到标签ID。

这种方法有效,但对于一个次要功能来说,它过于繁琐,需要付出相当大的努力。因此,你可以在MySQL数据库的book表中为标签定义一个MySQL JSON字段:

CREATE TABLE `book` (
  `id` MEDIUMINT() UNSIGNED NOT NULL AUTO_INCREMENT,
  `title` VARCHAR(200) NOT NULL,
  `tags` JSON DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB;
登录后复制
登录后复制
登录后复制
登录后复制

MySQL JSON列不能有默认值,不能用作主键,不能用作外键,也不能有直接索引。

但是,使用MySQL 9.1,你可以对从JSON数据派生的生成列创建函数索引,这使得能够索引JSON文档中的特定元素。这些生成的列可以是虚拟的或存储的,并作为辅助索引进行索引。

ALTER TABLE book
ADD COLUMN first_tag VARCHAR(50) AS (JSON_UNQUOTE(tags->'$[0]')),
ADD INDEX idx_first_tag (first_tag);
登录后复制
登录后复制
登录后复制
登录后复制

添加JSON数据

How to Use JSON Data Fields in MySQL Databases

可以在INSERT或UPDATE语句中传入整个JSON文档,从而可以轻松地将JSON移动到MySQL进行存储和操作。

例如,我们的书籍标签可以作为数组(在字符串内)传递:

INSERT INTO `book` (`title`, `tags`)
VALUES (
  'ECMAScript 2015: A SitePoint Anthology',
  '["JavaScript", "ES2015", "JSON"]'
);
登录后复制
登录后复制
登录后复制
登录后复制

也可以使用以下函数创建JSON:

  • JSON_ARRAY() 函数,用于创建数组。例如:-- 返回[1, 2, "abc"]:SELECT JSON_ARRAY(1, 2, 'abc');
  • JSON_OBJECT() 函数,用于创建对象。例如:-- 返回{"a": 1, "b": 2}:SELECT JSON_OBJECT('a', 1, 'b', 2);
  • JSON_QUOTE() 函数,用于将字符串作为JSON值引用。例如:-- 返回"[1, 2, "abc"]":SELECT JSON_QUOTE('[1, 2, "abc"]');
  • CAST(anyValue AS JSON) 函数,用于将值转换为JSON类型以确保有效性:SELECT CAST('{"a": 1, "b": 2}' AS JSON);

JSON_TYPE()函数允许你检查JSON值的类型。它应该返回OBJECT、ARRAY、标量类型(INTEGER、BOOLEAN等)、NULL或错误。例如:

-- 返回ARRAY:
SELECT JSON_TYPE('[1, 2, "abc"]');

-- 返回OBJECT:
SELECT JSON_TYPE('{"a": 1, "b": 2}');

-- 返回错误:
SELECT JSON_TYPE('{"a": 1, "b": 2');
登录后复制

JSON_VALID()函数如果JSON有效则返回1,否则返回0:

-- 返回1:
SELECT JSON_TYPE('[1, 2, "abc"]');

-- 返回1:
SELECT JSON_TYPE('{"a": 1, "b": 2}');

-- 返回0:
SELECT JSON_TYPE('{"a": 1, "b": 2');
登录后复制

尝试插入无效的JSON文档将引发错误,并且不会插入/更新整个记录。

在MySQL JSON列中搜索JSON文档

How to Use JSON Data Fields in MySQL Databases

使用JSON_CONTAINS()函数等MySQL JSON函数,可以检查JSON文档是否包含特定值。找到匹配项时返回1。例如:

-- 所有带有“JavaScript”标签的书籍:
SELECT * FROM `book` WHERE JSON_CONTAINS(tags, '["JavaScript"]');
登录后复制

JSON_SEARCH()函数返回JSON文档中值的路径。没有匹配项时返回NULL。

你还可以通过传递“one”和“all”标志以及搜索字符串来指定是否需要查找所有匹配项或单个匹配项(其中%与任意数量的字符匹配,_与LIKE一样匹配一个字符)。例如:

-- 所有标签以“Java”开头的书籍:
SELECT * FROM `book` WHERE JSON_SEARCH(tags, 'one', 'Java%') IS NOT NULL;
登录后复制

JSON_TABLE()函数将JSON数据转换为关系格式,以便更容易查询:

SELECT * 
FROM JSON_TABLE(
    '[{"tag": "SQL"}, {"tag": "JSON"}]', 
    '$[*]' COLUMNS (tag VARCHAR(50) PATH '$.tag')
) AS tags_table;
登录后复制

JSON路径

使用JSON_EXTRACT()函数的MySQL JSON查询可以根据指定的路径从JSON文档中检索特定值。

CREATE TABLE `book` (
  `id` MEDIUMINT() UNSIGNED NOT NULL AUTO_INCREMENT,
  `title` VARCHAR(200) NOT NULL,
  `tags` JSON DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB;
登录后复制
登录后复制
登录后复制
登录后复制

所有路径定义都以$开头,后跟其他选择器:

  • 一个句点后跟一个名称,例如$.website
  • [N],其中N是零索引数组中的位置
  • .[*]通配符评估对象的全部成员
  • [*]通配符评估数组的全部成员
  • prefix**suffix通配符评估所有以命名前缀开头并以命名后缀结尾的路径

以下示例指的是以下JSON文档:

ALTER TABLE book
ADD COLUMN first_tag VARCHAR(50) AS (JSON_UNQUOTE(tags->'$[0]')),
ADD INDEX idx_first_tag (first_tag);
登录后复制
登录后复制
登录后复制
登录后复制

路径示例:

  • $.a 返回 1
  • $.c 返回 [3, 4]
  • $.c[1] 返回 4
  • $.d.e 返回 5
  • $**.e 返回 [5]

你可以使用JSON提取MySQL函数有效地从你的book表中提取名称和第一个标签:

INSERT INTO `book` (`title`, `tags`)
VALUES (
  'ECMAScript 2015: A SitePoint Anthology',
  '["JavaScript", "ES2015", "JSON"]'
);
登录后复制
登录后复制
登录后复制
登录后复制

对于更复杂的示例,假设你有一个包含JSON配置文件数据的用户表。例如:

id name profile
1 Craig { "email": ["craig@email1.com", "craig@email2.com"], "twitter": "@craigbuckler" }
2 SitePoint { "email": [], "twitter": "@sitepointdotcom" }

你可以使用JSON路径提取Twitter名称。例如:

CREATE TABLE `book` (
  `id` MEDIUMINT() UNSIGNED NOT NULL AUTO_INCREMENT,
  `title` VARCHAR(200) NOT NULL,
  `tags` JSON DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB;
登录后复制
登录后复制
登录后复制
登录后复制

你可以在WHERE子句中使用JSON路径,只返回有Twitter帐户的用户:

ALTER TABLE book
ADD COLUMN first_tag VARCHAR(50) AS (JSON_UNQUOTE(tags->'$[0]')),
ADD INDEX idx_first_tag (first_tag);
登录后复制
登录后复制
登录后复制
登录后复制

修改JSON文档的一部分

How to Use JSON Data Fields in MySQL Databases

有几个MySQL函数可以使用路径表示法修改JSON文档的一部分。这些函数包括:

  • JSON_SET(doc, path, val[, path, val]…): 在文档中插入或更新数据。UPDATE book SET tags = JSON_SET(tags, '$[0]', 'Updated Tag');
  • JSON_INSERT(doc, path, val[, path, val]…): 在文档中插入数据,而不覆盖现有值。UPDATE book SET tags = JSON_INSERT(tags, '$[0]', 'New Tag');
  • JSON_REPLACE(doc, path, val[, path, val]…): 替换文档中的数据。UPDATE book SET tags = JSON_REPLACE(tags, '$[0]', 'Replaced Tag');
  • JSON_MERGE_PATCH(doc, doc[, doc]…): 合并两个或多个JSON文档,用后续文档的值替换现有键。UPDATE book SET tags = JSON_MERGE_PATCH(tags, '["technical"]') WHERE JSON_SEARCH(tags, 'one', 'JavaScript') IS NOT NULL;
  • JSON_ARRAY_APPEND(doc, path, val[, path, val]…): 将值追加到数组的末尾。UPDATE book SET tags = JSON_ARRAY_APPEND(tags, '$', 'New Tag');
  • JSON_ARRAY_INSERT(doc, path, val[, path, val]…): 在JSON数组中的特定位置插入值。UPDATE book SET tags = JSON_ARRAY_INSERT(tags, '$[0]', 'Inserted Tag');
  • JSON_REMOVE(doc, path[, path]…): 从文档中删除数据。UPDATE book SET tags = JSON_REMOVE(tags, '$[1]');
  • JSON_PRETTY(val): 美化JSON文档,使其更易于阅读。SELECT JSON_PRETTY('{"name": "SitePoint", "tags": ["MySQL", "JSON"]}');

例如,如果你想为任何已经具有“JavaScript”标签的书籍添加“technical”标签,可以使用JSON_MERGE_PATCH()函数:

INSERT INTO `book` (`title`, `tags`)
VALUES (
  'ECMAScript 2015: A SitePoint Anthology',
  '["JavaScript", "ES2015", "JSON"]'
);
登录后复制
登录后复制
登录后复制
登录后复制

更多信息

MySQL文档提供了关于MySQL JSON数据类型和相关JSON函数的详细信息。

再次提醒,除非绝对必要,否则不要使用JSON。你可以在MySQL中模拟整个面向文档的NoSQL数据库,但这会抵消SQL的许多好处,你不如直接切换到真正的NoSQL系统!

也就是说,对于SQL应用程序中更模糊的数据需求,JSON数据类型可能会节省一些工作量。

关于在MySQL中使用JSON数据的常见问题

你可以在MySQL中使用JSON吗?

MySQL通过提供JSON数据类型来支持JSON,该类型用于在列中存储JSON格式的数据。从MySQL 5.7.8开始,你可以创建带有JSON列的表,允许你使用SQL插入、更新和查询JSON数据。MySQL提供了一系列JSON函数来处理这些列中的JSON数据,从而可以提取、修改和操作JSON数据。

此外,你可以在SQL查询中使用JSON数据,在需要时使用JSON_TABLE等函数将其转换为关系数据。但是,重要的是要理解,MySQL从根本上来说是一个关系型数据库,其JSON数据类型支持旨在促进在关系上下文中处理JSON数据,而不是成为一个成熟的NoSQL JSON数据库。

如上文所述,仅仅因为你可以存储JSON,并不意味着你应该这样做:规范化是一种用于优化数据库结构的技术。第一范式(1NF)规则规定每一列都应该保存单个值——而存储多值JSON文档违反了这一规则。

在MySQL中存储JSON是否可以?

在以下情况下,在MySQL中存储JSON是可以的:

  • 半结构化或动态数据,不适合严格的模式。
  • 自定义属性,其中关系设计效率低下。
  • 与JSON API集成,用于存储有效载荷或日志。

但是,JSON不应替代结构化和经常查询数据的规范化关系存储。虽然MySQL 9.1通过函数索引和JSON_TABLE等功能改进了JSON功能,但对于大型数据集或复杂查询,JSON操作仍然可能会带来开销。

如何在MySQL查询中使用JSON?

你可以通过使用MySQL的JSON函数在MySQL查询中使用JSON。这些函数使你能够提取、操作和查询存储在JSON列或数据库中JSON格式字符串中的JSON数据。要访问JSON列中的JSON数据,请使用->运算符,后跟所需JSON元素的路径。

JSON_EXTRACT、JSON_SET和JSON_OBJECTAGG等JSON函数允许你过滤、修改、聚合和处理JSON数据。你还可以使用WHERE子句根据JSON值过滤行。MySQL的JSON功能提供了一种灵活的方式来直接在数据库查询中交互和操作JSON对象。

何时在MySQL中使用JSON?

你应该在以下情况下在MySQL中使用JSON:

  1. 半结构化数据:处理不可预测或稀疏字段(例如自定义属性)时使用JSON。
  2. 动态模式:当数据需求频繁变化时,JSON提供灵活性。
  3. 层次结构或嵌套数据:JSON支持具有父子关系或数组的数据。
  4. API集成:将有效载荷、响应或日志存储为JSON文档。

但是,避免在以下情况下使用JSON:

  • 需要索引的经常查询的字段(函数索引可以有所帮助,但关系设计通常更快)。
  • 需要规范化的严格关系数据。
  • 在JSON路径上的复杂查询会降低性能的情况。

如何在MySQL中存储JSON数据?

要在MySQL中存储JSON数据,你有两个主要选项。首先,你可以使用MySQL中引入的JSON数据类型来创建一个带有JSON列的表。此方法为JSON数据提供结构化存储和更好的查询性能。

或者,你可以在常规VARCHAR或TEXT列中将JSON数据存储为文本。当主要需要存储和检索JSON数据而无需复杂的数据库操作时,此方法适用。

如何在MySQL中索引JSON数据?

虽然你不能直接索引JSON列,但MySQL允许你对从JSON值派生的生成列创建函数索引。

例如,要索引JSON数组的第一个元素:

CREATE TABLE `book` (
  `id` MEDIUMINT() UNSIGNED NOT NULL AUTO_INCREMENT,
  `title` VARCHAR(200) NOT NULL,
  `tags` JSON DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB;
登录后复制
登录后复制
登录后复制
登录后复制

此方法提高了对经常访问的JSON路径的查询性能。

对于JSON数据,你应该使用MySQL还是NoSQL数据库?

这取决于你的项目需求:

  • 如果你需要关系存储,偶尔处理半结构化数据、自定义属性或关系模型中的层次结构数据,请选择MySQL。
  • 如果你的项目涉及大量的JSON存储、灵活的模式和以文档为基础的操作作为主要用例,请选择NoSQL数据库(如MongoDB)。

MySQL的JSON支持非常适合混合工作负载,但不能完全替代专门用于文档存储的NoSQL数据库。

如何从MySQL JSON字段中提取特定值?

要从MySQL JSON字段中提取特定值,请使用JSON_EXTRACT()函数或简写->运算符。

ALTER TABLE book
ADD COLUMN first_tag VARCHAR(50) AS (JSON_UNQUOTE(tags->'$[0]')),
ADD INDEX idx_first_tag (first_tag);
登录后复制
登录后复制
登录后复制
登录后复制

如何查询和过滤MySQL JSON字段中的数据?

要查询和过滤存储在MySQL JSON字段中的数据,可以使用JSON_CONTAINS()和JSON_SEARCH()等函数。你还可以使用JSON_EXTRACT()检索特定值以进行进一步过滤。

INSERT INTO `book` (`title`, `tags`)
VALUES (
  'ECMAScript 2015: A SitePoint Anthology',
  '["JavaScript", "ES2015", "JSON"]'
);
登录后复制
登录后复制
登录后复制
登录后复制

以上是如何在MySQL数据库中使用JSON数据字段的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板