为什么使用JSON
MySQL5.7增加了JSON数据类型的支持,当 MySQL 引入 JSON 数据类型前已经满足了多样的数据库需求时,为什么还需要使用 JSON 。
让我们举个例子说明
通常,我们可能会创建一个单独的数据库表,包含 id , user_id , key ,以及 value 字段,或者保存为一个格式化的字符串,在程序执行时再进行解析。
然而,这对于少量用户是很好的。如果我们有 1000 个用户和 5 个配置项,则需要查看一个具有 5000 条记录的表,但这只是我们应用非常小的一个功能。或者我们正在使用格式化的字符串,多余的解析代码只会增加服务器的负载。这种情况下,使用 JSON 数据类型来保存用户的配置可以节省数据库表空间,并将单独保存的记录数减少到与用户数相同。而且,我们还能够获得不用编写任何 JSON 的解析代码的好处,因为 ORM 或者语言运行库会进行相应的处理。
CRUD操作
首先我们创建一张表products
CREATE TABLE `e_store`.`products`(`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,`name` VARCHAR(250) NOT NULL ,`brand_id` INT UNSIGNED NOT NULL ,`category_id` INT UNSIGNED NOT NULL ,`attributes` JSON NOT NULL ,PRIMARY KEY(`id`) ,INDEX `CATEGORY_ID`(`category_id` ASC) ,INDEX `BRAND_ID`(`brand_id` ASC));
attributes 字段的列类型已经被声明为 JSON,这是现在 MySQL 中一种可用的本地化数据类型。它允许我们在 MySQL 里给 attributes 字段使用各种与 JSON 相关的数据结构。
插入
INSERT INTO `e_store`.`products`(`name` ,`brand_id` ,`category_id` ,`attributes`)VALUES('Prime' ,'1' ,'1' ,'{"screen": "50 inch", "resolution": "2048 x 1152 pixels", "ports": {"hdmi": 1, "usb": 3}, "speakers": {"left": "10 watt", "right": "10 watt"}}');
我们也可以使用内置的 JSON_OBJECT 函数来创建 JSON 对象。
JSON_OBJECT 函数接受 JSON_OBJECT(key1, value1, key2, value2, ... key(n), value(n)) 形式的键值对列表来返回一个 JSON 对象。
INSERT INTO `e_store`.`products`(`name` ,`brand_id` ,`category_id` ,`attributes`)VALUES('Desire' ,'2' ,'2' ,JSON_OBJECT("network" ,JSON_ARRAY("GSM" , "CDMA" , "HSPA" , "EVDO") ,"body" ,"5.11 x 2.59 x 0.46 inches" ,"weight" ,"143 grams" ,"sim" ,"Micro-SIM" ,"display" ,"4.5 inches" ,"resolution" ,"720 x 1280 pixels" ,"os" ,"Android Jellybean v4.3"));
JSON_ARRAY
函数接受到一组值会返回一个 JSON 数组。如果多次指定相同的键,只会保留第一个键值对。这是 MySQL 内部对 JSON 的规范。此外,作为规范的一部分,当对象被排序时,键值对之间的留白会被移除。
我们用来创建 JSON 对象的另一个函数是 JSON_MERGE
。JSON_MERGE
函数接受多个 JSON 对象,并生成一个单独的聚合对象。
INSERT INTO `e_store`.`products`(`name` ,`brand_id` ,`category_id` ,`attributes`)VALUES('Explorer' ,'3' ,'3' ,JSON_MERGE('{"sensor_type": "CMOS"}' ,'{"processor": "Digic DV III"}' ,'{"scanning_system": "progressive"}' ,JSON_OBJECT("mount_type" , "PL") ,'{"monitor_type": "LCD"}'));
在 JSON_MERGE
函数的情形下,如果一个键被重复添加多次,它的值会作为一个数组保留在输出中。
SELECT JSON_MERGE('{"network": "GSM"}' ,'{"network": "CDMA"}' ,'{"network": "HSPA"}' ,'{"network": "EVDO"}');

读取
对于非 JSON 类型的典型 MySQL 值,where
子句是非常直接的。只要指定列,运算符,和需要处理的值就行了。然而当处理 JSON 列时,这样的 where
子句不起作用:
SELECT*FROM`e_store`.`products`WHEREattributes = '{"ports": {"usb": 3, "hdmi": 1}, "screen": "50 inch", "speakers": {"left": "10 watt", "right": "10 watt"}, "resolution": "2048 x 1152 pixels"}';
当我们想用JSON字段作为查询条件时,应该使用路径表达式。
JSON_EXTRACT
函数 ,它接收一个路径表达式来做为读取 JSON 数据的参数。
SELECT*FROM`e_store`.`products`WHERE`category_id` = 1AND JSON_EXTRACT(`attributes` , '$.ports.usb') > 0AND JSON_EXTRACT(`attributes` , '$.ports.hdmi') > 0;
JSON_EXTRACT 函数的第一个参数是应用路径表达式为 attributes 对应的列的 JSON。$ 符号表示要处理的对象。 $.ports.usb 和 $.ports.hdmi 路径表达式可以分别翻译为 “获取 ports 下的 usb 的值” 和 “获取 ports 下的 hdmi 的值”。
JSON_EXTRACT
函数还有一个别名 ->
,我们可以用这个别名来使你的查询语句可读性更好。
修改我们之前的查询语句。
SELECT*FROM`e_store`.`products`WHERE`category_id` = 1AND `attributes` -> '$.ports.usb' > 0AND `attributes` -> '$.ports.hdmi' > 0;
更新
为了更新 JSON 的值,我们将使用 JSON_INSERT
, JSON_REPLACE
,JSON_SET
这几个函数。这些函数还需要一个路径表达式来指定要修改的 JSON 对象的哪些部分。这些函数的返回值是一个更改之后的合法的 JSON 对象。
UPDATE `e_store`.`products`SET `attributes` = JSON_INSERT(`attributes` ,'$.chipset' ,'Qualcomm')WHERE`category_id` = 2;

$.chipset
变量定义了 chipset
属性的位置是在这个对象的最底部。
接下来,让我们使用 JSON_REPLACE
函数,来更新 chipset
属性,使其变的更具描述性。
UPDATE `e_store`.`products`SET `attributes` = JSON_REPLACE(`attributes` ,'$.chipset' ,'Qualcomm Snapdragon')WHERE`category_id` = 2;

JSON_INSERT 函数只有当属性不存在的时候,它才会将这个属性添加到对象中。
JSON_REPLACE 函数只有在对象中找到该属性才会替换该属性。
JSON_SET 函数,如果在对象中没有找到这个属性,就会添加这个属性到对象中,如果对象中有这个属性了,就会替换掉原来的属性。
删除
关于删除操作我们将会关注两个点。
第一个点是从 JSON 列中删除某个 键 / 值(JSON_REMOVE),第二个点是从 JSON 列中删除某些行(JSON_EXTRACT)。
UPDATE `e_store`.`products`SET `attributes` = JSON_REMOVE(`attributes` , '$.mount_type')WHERE`category_id` = 3;
删除了属性中mount_type的键值对




