MySQL 5.7 新特性 JSON 的创建,插入,查询,更新


作者: 我不是鱼 (2016-08-31 16:13)分类: MySQL   标签: MySQL JSON MySQL JSON 应用

从 MySQL 5.7.8 开始,MySQL 支持原生的 JSON 数据类型。

创建 JSON

类似 varchar,设置 JSON 主要将字段的 type 是 json, 不能设置长度,可以是 NULL  但不能有默认值。

mysql> CREATE TABLE lnmp (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `category` JSON,
    `tags` JSON,
    PRIMARY KEY (`id`)
);

mysql> DESC lnmp;
+----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| category | json | YES | | NULL | |
| tags | json | YES | | NULL | |
+----------+------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

这样 JSON 的字段就创建好了。

插入 JSON

就是插入 json 格式的字符串,可以是对象的形式,也可以是数组的形式

mysql> INSERT INTO `lnmp` (category, tags) VALUES ('{"id": 1, "name": "lnmp.cn"}', '[1, 2, 3]');
Query OK, 1 row affected (0.01 sec)

MySQL 也有专门的函数 JSON_OBJECT,JSON_ARRAY 生成 json 格式的数据

mysql> INSERT INTO `lnmp` (category, tags) VALUES (JSON_OBJECT("id", 2, "name", "php.net"), JSON_ARRAY(1, 3, 5));
Query OK, 1 row affected (0.00 sec)

查看插入的数据

mysql> SELECT * FROM lnmp;
+----+------------------------------+-----------+
| id | category | tags |
+----+------------------------------+-----------+
| 1 | {"id": 1, "name": "lnmp.cn"} | [1, 2, 3] |
| 2 | {"id": 2, "name": "php.net"} | [1, 3, 5] |
+----+------------------------------+-----------+
2 rows in set (0.00 sec)

更多生成 JSON 值的函数请参考: http://dev.mysql.com/doc/refman/5.7/en/json-creation-functions.html

查询 JSON

查询 json 中的数据用 column->path 的形式,其中对象类型 path 这样表示 $.path, 而数组类型则是 $[index]

mysql> SELECT id, category->'$.id', category->'$.name', tags->'$[0]', tags->'$[2]' FROM lnmp;
+----+------------------+--------------------+--------------+--------------+
| id | category->'$.id' | category->'$.name' | tags->'$[0]' | tags->'$[2]' |
+----+------------------+--------------------+--------------+--------------+
| 1 | 1 | "lnmp.cn" | 1 | 3 |
| 2 | 2 | "php.net" | 1 | 5 |
+----+------------------+--------------------+--------------+--------------+
2 rows in set (0.00 sec)

可以看到对应字符串类型的 category->'$.name' 中还包含着双引号,这其实并不是想要的结果,可以用 JSON_UNQUOTE 函数将双引号去掉,从 MySQL 5.7.13 起也可以通过这个操作符 ->> 这个和 JSON_UNQUOTE 是等价的

mysql> SELECT id, category->'$.name', JSON_UNQUOTE(category->'$.name'), category->>'$.name' FROM lnmp;
+----+--------------------+----------------------------------+---------------------+
| id | category->'$.name' | JSON_UNQUOTE(category->'$.name') | category->>'$.name' |
+----+--------------------+----------------------------------+---------------------+
| 1 | "lnmp.cn" | lnmp.cn | lnmp.cn |
| 2 | "php.net" | php.net | php.net |
+----+--------------------+----------------------------------+---------------------+
2 rows in set (0.00 sec)

下面说下 JSON 作为条件进行搜索。因为 JSON 不同于字符串,所以如果用字符串和 JSON 字段比较,是不会相等的

mysql> SELECT * FROM lnmp WHERE category = '{"id": 1, "name": "lnmp.cn"}';
Empty set (0.00 sec)

这时可以通过 CAST 将字符串转成 JSON 的形式

mysql> SELECT * FROM lnmp WHERE category = CAST('{"id": 1, "name": "lnmp.cn"}' as JSON);
+----+------------------------------+-----------+
| id | category | tags |
+----+------------------------------+-----------+
| 1 | {"id": 1, "name": "lnmp.cn"} | [1, 2, 3] |
+----+------------------------------+-----------+
1 row in set (0.00 sec)

通过 JSON 中的元素进行查询, 对象型的查询同样可以通过 column->path

mysql> SELECT * FROM lnmp WHERE category->'$.name' = 'lnmp.cn';
+----+------------------------------+-----------+
| id | category | tags |
+----+------------------------------+-----------+
| 1 | {"id": 1, "name": "lnmp.cn"} | [1, 2, 3] |
+----+------------------------------+-----------+
1 row in set (0.00 sec)

上面有提到 column->path 形式从 select 中查询出来的字符串是包含双引号的,但作为条件这里其实没什么影响,-> 和 ->> 结果是一样的

mysql> SELECT * FROM lnmp WHERE category->>'$.name' = 'lnmp.cn';
+----+------------------------------+-----------+
| id | category | tags |
+----+------------------------------+-----------+
| 1 | {"id": 1, "name": "lnmp.cn"} | [1, 2, 3] |
+----+------------------------------+-----------+
1 row in set (0.00 sec)

要特别注意的是,JSON 中的元素搜索是严格区分变量类型的,比如说整型和字符串是严格区分的

mysql> SELECT * FROM lnmp WHERE category->'$.id' = '1';
Empty set (0.00 sec)

mysql> SELECT * FROM lnmp WHERE category->'$.id' = 1;
+----+------------------------------+-----------+
| id | category | tags |
+----+------------------------------+-----------+
| 1 | {"id": 1, "name": "lnmp.cn"} | [1, 2, 3] |
+----+------------------------------+-----------+
1 row in set (0.00 sec)

可以看到搜索字符串 1 和整型 1 的结果是不一样的。

除了用 column->path 的形式搜索,还可以用JSON_CONTAINS 函数,但和 column->path 的形式有点相反的是,JSON_CONTAINS 第二个参数是不接受整数的,无论 json 元素是整型还是字符串,否则会出现这个错误

mysql> SELECT * FROM lnmp WHERE JSON_CONTAINS(category, 1, '$.id');
ERROR 3146 (22032): Invalid data type for JSON data in argument 2 to function json_contains; a JSON string or JSON type is required.

这里必须是要字符串 1

mysql> SELECT * FROM lnmp WHERE JSON_CONTAINS(category, '1', '$.id');
+----+------------------------------+-----------+
| id | category | tags |
+----+------------------------------+-----------+
| 1 | {"id": 1, "name": "lnmp.cn"} | [1, 2, 3] |
+----+------------------------------+-----------+
1 row in set (0.01 sec)

对于数组类型的 JSON 的查询,比如说 tags 中包含有 2 的数据,同样要用 JSON_CONTAINS 函数,同样第二个参数也需要是字符串

mysql> SELECT * FROM lnmp WHERE JSON_CONTAINS(tags, '2');
+----+------------------------------+-----------+
| id | category | tags |
+----+------------------------------+-----------+
| 1 | {"id": 1, "name": "lnmp.cn"} | [1, 2, 3] |
+----+------------------------------+-----------+
1 row in set (0.00 sec)

更多搜索 JSON 值的函数请参考:http://dev.mysql.com/doc/refman/5.7/en/json-search-functions.html

更新 JSON

如果是整个 json 更新的话,和插入时类似的。

mysql> UPDATE lnmp SET tags = '[1, 3, 4]' WHERE id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT * FROM lnmp;
+----+------------------------------+-----------+
| id | category | tags |
+----+------------------------------+-----------+
| 1 | {"id": 1, "name": "lnmp.cn"} | [1, 3, 4] |
| 2 | {"id": 2, "name": "php.net"} | [1, 3, 5] |
+----+------------------------------+-----------+
2 rows in set (0.00 sec)

但如果要更新 JSON 下的元素,MySQL 并不支持 column->path 的形式

mysql> UPDATE lnmp SET category->'$.name' = 'lnmp', tags->'$[0]' = 2 WHERE id = 1;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '->'$.name' = 'lnmp', tags->'$[0]' = 2 WHERE id = 1' at line 1

则可能要用到以下几个函数

JSON_INSERT() 插入新值,但不会覆盖已经存在的值

mysql> UPDATE lnmp SET category = JSON_INSERT(category, '$.name', 'lnmp', '$.url', 'www.lnmp.cn') WHERE id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT * FROM lnmp;
+----+----------------------------------------------------+-----------+
| id | category | tags |
+----+----------------------------------------------------+-----------+
| 1 | {"id": 1, "url": "www.lnmp.cn", "name": "lnmp.cn"} | [1, 3, 4] |
| 2 | {"id": 2, "name": "php.net"} | [1, 3, 5] |
+----+----------------------------------------------------+-----------+
2 rows in set (0.00 sec)

可以看到 name 没有被修改,但新元素 url 已经添加进去

JSON_SET() 插入新值,并覆盖已经存在的值

mysql> UPDATE lnmp SET category = JSON_SET(category, '$.host', 'www.lnmp.cn', '$.url', 'http://www.lnmp.cn') WHERE id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT * FROM lnmp;
+----+----------------------------------------------------------------------------------+-----------+
| id | category | tags |
+----+----------------------------------------------------------------------------------+-----------+
| 1 | {"id": 1, "url": "http://www.lnmp.cn", "host": "www.lnmp.cn", "name": "lnmp.cn"} | [1, 3, 4] |
| 2 | {"id": 2, "name": "php.net"} | [1, 3, 5] |
+----+----------------------------------------------------------------------------------+-----------+
2 rows in set (0.00 sec)

可以看到 host 已经插入,url 已经被修改

JSON_REPLACE() 只替换存在的值

mysql> UPDATE lnmp SET category = JSON_REPLACE(category, '$.name', 'php', '$.url', 'http://www.php.net') WHERE id = 2;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT * FROM lnmp;
+----+----------------------------------------------------------------------------------+-----------+
| id | category | tags |
+----+----------------------------------------------------------------------------------+-----------+
| 1 | {"id": 1, "url": "http://www.lnmp.cn", "host": "www.lnmp.cn", "name": "lnmp.cn"} | [1, 3, 4] |
| 2 | {"id": 2, "name": "php"} | [1, 3, 5] |
+----+----------------------------------------------------------------------------------+-----------+
2 rows in set (0.00 sec)

可以看到 name 已经被替换,url 不存在被忽略。

JSON_REMOVE() 删除 JSON 元素

mysql> UPDATE lnmp SET category = JSON_REMOVE(category, '$.url', '$.host') WHERE id = 1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT * FROM lnmp;
+----+------------------------------+-----------+
| id | category | tags |
+----+------------------------------+-----------+
| 1 | {"id": 1, "name": "lnmp.cn"} | [1, 3, 4] |
| 2 | {"id": 2, "name": "php"} | [1, 3, 5] |
+----+------------------------------+-----------+
2 rows in set (0.00 sec)

更多函数请参考:http://dev.mysql.com/doc/refman/5.7/en/json-modification-functions.html

MySQL JSON 在 PHP 中的表现

虽然在 MySQL 是个JSON 类型,但实际在 PHP 应用中返回的是 JSON 格式的字符串

array(2) {
[0]=>
array(3) {
["id"]=>
string(1) "1"
["category"]=>
string(28) "{"id": 1, "name": "lnmp.cn"}"
["tags"]=>
string(9) "[1, 3, 4]"
}
[1]=>
array(3) {
["id"]=>
string(1) "2"
["category"]=>
string(24) "{"id": 2, "name": "php"}"
["tags"]=>
string(9) "[1, 3, 5]"
}
}

[转帖 ]MySQL 5.7 新特性 JSON的更多相关文章

  1. MySQL 8.0 新特性梳理汇总

    一 历史版本发布回顾 从上图可以看出,基本遵循 5+3+3 模式 5---GA发布后,5年 就停止通用常规的更新了(功能不再更新了): 3---企业版的,+3年功能不再更新了: 3 ---完全停止更新 ...

  2. Mysql 8.0 新特性测试

    Mysql 8.0 新特性测试 Role MySQL8.0版本添加了role特性,role是一种逻辑概念是权限的集合,可以将一个或以上的权限赋予给role,再将role赋给user.Oracle,Po ...

  3. 初识 MySQL 5.6 新特性、功能

    背景: 之前介绍过 MySQL 5.5 新功能.参数,现在要用MySQL5.6,所以就学习和了解下MySQL5.6新的特性和功能,尽量避免踩坑.在后续的学习过程中文章也会不定时更新. 一:参数默认值的 ...

  4. MySql 5.7 新特性概览

    安全的提升 1.1 在Mysql 8版本中,caching_sha2_password 是一个缺省的认证插见.5.7 版本的客户端支持 caching_sha2_password 的客户端认证. 1. ...

  5. 总结一下关于mysql 5.6 新特性

    一直断断续续的看一些mysql特性,今天总结一下,以下是列表,网址 http://mariadb.org/ (也是类似的特性), http://mysql.com/ 最近在看关于mysql新特性的一些 ...

  6. MySQL 5.7新特性之Generated Column(函数索引)

    MySQL 5.7引入了Generated Column,这篇文章简单地介绍了Generated Column的使用方法和注意事项,为读者了解MySQL 5.7提供一个快速的.完整的教程.这篇文章围绕 ...

  7. MySQL 5.7新特性之generated column

    MySQL 5.7引入了generated column,这篇文章简单地介绍了generated column的使用方法和注意事项,为读者了解MySQL 5.7提供一个快速的.完整的教程.这篇文章围绕 ...

  8. MySQL 5.6新特性 -- Multi-Range Read

    如果基表很大,数据没有被缓存,在二级索引上使用范围扫描读取行可能会导致大量的随机磁盘访问.使用Multi-Range Read新特性,mysql可以减少对磁盘的随机读的次数:首先,mysql只是扫描索 ...

  9. MySQL 5.7新特性介绍

    本文是基于MySQL-5.7.7-rc版本,未来可能 还会发生更多变化. 1.即将删除的特性1.1.InnoDB monitoring features,详见:WL#7377(访问地址:http:// ...

随机推荐

  1. spring里头各种获取ApplicationContext的方法

    为啥写这个文章呢?spring各个版本不同,以及和系统框架套在一起不同,导致获取的方式不同,网络上各种版本,太乱了,写获取方式的人都不写这个获取方式是在本地还是在WEB,在那种应用服务器下,在spri ...

  2. [CSS] No selectable effect

    .noselect { -webkit-touch-callout: none; /* iOS Safari */ -webkit-user-select: none; /* Chrome/Safar ...

  3. ios开发清除SDWebImage图片缓存

    一:一般在实际的项目应用中都会用到第三方框架SDWebImage去下载缓存图片,但在ios开发应用中,常常涉及对SDWebImage缓存图片的清除.本文所列出代码即是对SDWebImage缓存图片的清 ...

  4. javascript中定义事件的三种方式 分类: C1_HTML/JS/JQUERY 2014-08-07 10:27 634人阅读 评论(0) 收藏

    在javascript中,可以为某个元素指定事件,指定的方式有以下三种: 1.在html中,使用onclick属性 2.在javascript中,使用onclick属性 3.在javascipt中,使 ...

  5. Linux系统下的单调时间函数

    欢迎转载,转载请注明出处:http://forever.blog.chinaunix.net 一.编写linux下应用程序的时候,有时候会用到高精度相对时间的概念,比如间隔100ms.那么应该使用哪个 ...

  6. [Java][web]利用Spring随时随地获得Request和Session

    利用Spring随时随地获得Request和Session 一.准备工作: 在web.xml中加入 <listener> <listener-class> org.spring ...

  7. windows下python安装uwsgi

    1.使用pip安装 pip install uwsgi 报错:os没有uname() 解决: 定位到uwsgiconfig.py文件中,首先import platform后,将os.unam()都改为 ...

  8. php字符串转时间戳

    PHP 提供了函数可以方便的将各种形式的日期转换为时间戳,该类函数主要是: strtotime():将任何英文文本的日期时间描述解析为时间戳. mktime():从日期取得时间戳. strtotime ...

  9. JavaStuNote 4

    装箱(inbox)和拆箱(outbox) 代表了类类型和基本类型之间的转换行为. 手动版本号: Integer b = new Integer(10); Int a = b.intValue; 自己主 ...

  10. web开发-MVC IoC 框架(转)

    随着Web应用的商业逻辑包含逐渐复杂的公式分析计算.决策支持等,使客户机越 来越不堪重负,因此将系统的商业分离出来.单独形成一部分,这样三层结构产生了. 其中‘层’是逻辑上的划分. 三层体系结构是将整 ...