### 12.18.7 JSON 模式验证函数 [](<>) 从 MySQL 8.0.17 开始,MySQL 支持针对符合以下标准的 JSON 模式验证 JSON 文档[JSON Schema 规范草案 4](https://json-schema.org/specification-links.html#draft-4).这可以使用本节中详述的任何一个函数来完成,这两个函数都有两个参数,一个 JSON 模式和一个根据模式验证的 JSON 文档。[`JSON_SCHEMA_VALID()`](json-validation-functions.html#function_json-schema-valid)如果文档对模式进行验证,则返回 true,否则返回 false;[`JSON_SCHEMA_VALIDATION_REPORT()`](json-validation-functions.html#function_json-schema-validation-report)提供 JSON 格式的验证报告。 这两个函数都处理空或无效输入,如下所示: - 如果至少有一个论点是`空值`, 函数返回`空值`. - 如果至少有一个参数不是有效的 JSON,则函数会引发错误 ([`ER_INVALID_TYPE_FOR_JSON`](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_invalid_type_for_json)) - 此外,如果架构不是有效的 JSON 对象,则函数返回[`ER_INVALID_JSON_TYPE`](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_invalid_json_type). MySQL 支持`必需的`JSON 模式中的属性以强制包含必需的属性(请参阅函数描述中的示例)。 MySQL 支持`id`,`$模式`,`描述`, 和`类型`JSON 模式中的属性,但不需要任何这些。 MySQL 不支持 JSON 模式中的外部资源;使用`$参考`关键词原因`JSON_SCHEMA_VALID()`失败[`ER_NOT_SUPPORTED_YET`](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_not_supported_yet). 笔记 MySQL 支持 JSON 模式中的正则表达式模式,它支持但默默地忽略无效模式(参见描述`JSON_SCHEMA_VALID()`例如)。 以下列表中详细描述了这些功能: - [](<>) [`JSON_SCHEMA_VALID(*`图式`*,*`文档`*)`](json-validation-functions.html#function_json-schema-valid) [](<>) 验证 JSON*`文档`*针对 JSON*`图式`*.两个都*`图式`*和*`文档`*是必要的。架构必须是有效的 JSON 对象;该文档必须是有效的 JSON 文档。前提是满足这些条件: 如果文档根据模式验证,则函数返回 true (1);否则,它返回 false (0)。 在这个例子中,我们设置了一个用户变量`@schema`到地理坐标的 JSON 模式的值,以及另一个`@文档`到包含一个这样的坐标的 JSON 文档的值。然后我们验证`@文档`根据验证`@schema`通过使用它们作为参数`JSON_SCHEMA_VALID()`: ``` mysql> SET @schema = '{ '> "id": "http://json-schema.org/geo", '> "$schema": "http://json-schema.org/draft-04/schema#", '> "description": "A geographical coordinate", '> "type": "object", '> "properties": { '> "latitude": { '> "type": "number", '> "minimum": -90, '> "maximum": 90 '> }, '> "longitude": { '> "type": "number", '> "minimum": -180, '> "maximum": 180 '> } '> }, '> "required": ["latitude", "longitude"] '>}'; Query OK, 0 rows affected (0.01 sec) mysql> SET @document = '{ '> "latitude": 63.444697, '> "longitude": 10.445118 '>}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_SCHEMA_VALID(@schema, @document); +---------------------------------------+ | JSON_SCHEMA_VALID(@schema, @document) | +---------------------------------------+ | 1 | +---------------------------------------+ 1 row in set (0.00 sec) ``` 自从`@schema`包含`必需的`属性,我们可以设置`@文档`到一个在其他方面有效但不包含所需属性的值,然后对其进行测试`@schema`, 像这样: ``` mysql> SET @document = '{}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_SCHEMA_VALID(@schema, @document); +---------------------------------------+ | JSON_SCHEMA_VALID(@schema, @document) | +---------------------------------------+ | 0 | +---------------------------------------+ 1 row in set (0.00 sec) ``` 如果我们现在设置`@schema`到相同的 JSON 模式,但没有`必需的`属性,`@文档`验证,因为它是一个有效的 JSON 对象,即使它不包含任何属性,如下所示: ``` mysql> SET @schema = '{ '> "id": "http://json-schema.org/geo", '> "$schema": "http://json-schema.org/draft-04/schema#", '> "description": "A geographical coordinate", '> "type": "object", '> "properties": { '> "latitude": { '> "type": "number", '> "minimum": -90, '> "maximum": 90 '> }, '> "longitude": { '> "type": "number", '> "minimum": -180, '> "maximum": 180 '> } '> } '>}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_SCHEMA_VALID(@schema, @document); +---------------------------------------+ | JSON_SCHEMA_VALID(@schema, @document) | +---------------------------------------+ | 1 | +---------------------------------------+ 1 row in set (0.00 sec) ``` [](<>)[](<>) [](<>)**JSON\_架构\_VALID() 和 CHECK 约束。**  `JSON_SCHEMA_VALID()`也可以用来强制`查看`约束。 考虑表格`地理`如此处所示创建,带有一个 JSON 列`协调`表示地图上的经纬度点,由用作参数的 JSON 模式控制`JSON_SCHEMA_VALID()`作为表达式传递的调用`查看`对该表的约束: ``` mysql> CREATE TABLE geo ( -> coordinate JSON, -> CHECK( -> JSON_SCHEMA_VALID( -> '{ '> "type":"object", '> "properties":{ '> "latitude":{"type":"number", "minimum":-90, "maximum":90}, '> "longitude":{"type":"number", "minimum":-180, "maximum":180} '> }, '> "required": ["latitude", "longitude"] '> }', -> coordinate -> ) -> ) -> ); Query OK, 0 rows affected (0.45 sec) ``` 笔记 因为一个 MySQL`查看`约束不能包含对变量的引用,您必须将 JSON 模式传递给`JSON_SCHEMA_VALID()`使用它为表指定这样的约束时是内联的。 我们将表示坐标的 JSON 值分配给三个变量,如下所示: ``` mysql> SET @point1 = '{"latitude":59, "longitude":18}'; Query OK, 0 rows affected (0.00 sec) mysql> SET @point2 = '{"latitude":91, "longitude":0}'; Query OK, 0 rows affected (0.00 sec) mysql> SET @point3 = '{"longitude":120}'; Query OK, 0 rows affected (0.00 sec) ``` 这些值中的第一个是有效的,如下所示[`插入`](insert.html)陈述: ``` mysql> INSERT INTO geo VALUES(@point1); Query OK, 1 row affected (0.05 sec) ``` 第二个 JSON 值无效,因此约束失败,如下所示: ``` mysql> INSERT INTO geo VALUES(@point2); ERROR 3819 (HY000): Check constraint 'geo_chk_1' is violated. ``` 在 MySQL 8.0.19 及更高版本中,您可以获得有关故障性质的精确信息——在这种情况下,`纬度`值超过了模式中定义的最大值——通过发出[`显示警告`](show-warnings.html)陈述: ``` mysql> SHOW WARNINGS\G *************************** 1. row *************************** Level: Error Code: 3934 Message: The JSON document location '#/latitude' failed requirement 'maximum' at JSON Schema location '#/properties/latitude'. *************************** 2. row *************************** Level: Error Code: 3819 Message: Check constraint 'geo_chk_1' is violated. 2 rows in set (0.00 sec) ``` 上面定义的第三个坐标值也是无效的,因为它缺少所需的`纬度`财产。和以前一样,您可以通过尝试将值插入`地理`表,然后发出`显示警告`然后: ``` mysql> INSERT INTO geo VALUES(@point3); ERROR 3819 (HY000): Check constraint 'geo_chk_1' is violated. mysql> SHOW WARNINGS\G *************************** 1. row *************************** Level: Error Code: 3934 Message: The JSON document location '#' failed requirement 'required' at JSON Schema location '#'. *************************** 2. row *************************** Level: Error Code: 3819 Message: Check constraint 'geo_chk_1' is violated. 2 rows in set (0.00 sec) ``` 看[第 13.1.20.6 节,“检查约束”](create-table-check-constraints.html), 了解更多信息。 [](<>) JSON Schema 支持为字符串指定正则表达式模式,但 MySQL 使用的实现会默默地忽略无效模式。这意味着`JSON_SCHEMA_VALID()`即使正则表达式模式无效,也可以返回 true,如下所示: ``` mysql> SELECT JSON_SCHEMA_VALID('{"type":"string","pattern":"("}', '"abc"'); +---------------------------------------------------------------+ | JSON_SCHEMA_VALID('{"type":"string","pattern":"("}', '"abc"') | +---------------------------------------------------------------+ | 1 | +---------------------------------------------------------------+ 1 row in set (0.04 sec) ``` - [](<>) [`JSON_SCHEMA_VALIDATION_REPORT(*`图式`*,*`文档`*)`](json-validation-functions.html#function_json-schema-validation-report) [](<>) 验证 JSON*`文档`*针对 JSON*`图式`*.两个都*`图式`*和*`文档`*是必要的。与 JSON 一样\_有效的\_SCHEMA(),架构必须是有效的 JSON 对象,文档必须是有效的 JSON 文档。如果满足这些条件,该函数会以 JSON 文档的形式返回关于验证结果的报告。如果 JSON 文档根据 JSON Schema 被认为是有效的,则该函数返回一个具有一个属性的 JSON 对象`有效的`具有“真”值。如果 JSON 文档验证失败,该函数将返回一个 JSON 对象,其中包括此处列出的属性: - `有效的`:对于失败的架构验证,始终为“假” - `原因`:包含失败原因的人类可读字符串 - `模式位置`:一个 JSON 指针 URI 片段标识符,指示在 JSON 模式中验证失败的位置(请参阅此列表后面的注释) - `文件位置`:一个 JSON 指针 URI 片段标识符,指示在 JSON 文档中验证失败的位置(请参阅此列表后面的注释) - `架构失败的关键字`: 一个字符串,包含违反的 JSON 模式中的关键字或属性的名称 [](<>) 笔记 JSON 指针 URI 片段标识符定义在[RFC 6901 - JavaScript 对象表示法 (JSON) 指针](https://tools.ietf.org/html/rfc6901#page-5).(这些是*不是*与使用的 JSON 路径表示法相同[`JSON_EXTRACT()`](json-search-functions.html#function_json-extract)和其他 MySQL JSON 函数。)在这种表示法中,`#`代表整个文档,并且`#/myprop`表示包含在名为的顶级属性中的文档部分`我的道具`.有关详细信息,请参阅刚刚引用的规范和本节后面显示的示例。 在这个例子中,我们设置了一个用户变量`@schema`到地理坐标的 JSON 模式的值,以及另一个`@文档`到包含一个这样的坐标的 JSON 文档的值。然后我们验证`@文档`根据验证`@schema`通过使用它们作为参数`JSON_SCHEMA_VALIDATION_REORT()`: ``` mysql> SET @schema = '{ '> "id": "http://json-schema.org/geo", '> "$schema": "http://json-schema.org/draft-04/schema#", '> "description": "A geographical coordinate", '> "type": "object", '> "properties": { '> "latitude": { '> "type": "number", '> "minimum": -90, '> "maximum": 90 '> }, '> "longitude": { '> "type": "number", '> "minimum": -180, '> "maximum": 180 '> } '> }, '> "required": ["latitude", "longitude"] '>}'; Query OK, 0 rows affected (0.01 sec) mysql> SET @document = '{ '> "latitude": 63.444697, '> "longitude": 10.445118 '>}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_SCHEMA_VALIDATION_REPORT(@schema, @document); +---------------------------------------------------+ | JSON_SCHEMA_VALIDATION_REPORT(@schema, @document) | +---------------------------------------------------+ | {"valid": true} | +---------------------------------------------------+ 1 row in set (0.00 sec) ``` 现在我们设置`@文档`这样它就为其属性之一指定了非法值,如下所示: ``` mysql> SET @document = '{ '> "latitude": 63.444697, '> "longitude": 310.445118 '> }'; ``` 验证`@文档`现在在测试时失败`JSON_SCHEMA_VALIDATION_REPORT()`.函数调用的输出包含有关失败的详细信息(函数由[`JSON_PRETTY()`](json-utility-functions.html#function_json-pretty)提供更好的格式),如下所示: ``` mysql> SELECT JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document))\G *************************** 1. row *************************** JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document)): { "valid": false, "reason": "The JSON document location '#/longitude' failed requirement 'maximum' at JSON Schema location '#/properties/longitude'", "schema-location": "#/properties/longitude", "document-location": "#/longitude", "schema-failed-keyword": "maximum" } 1 row in set (0.00 sec) ``` 自从`@schema`包含`必需的`属性,我们可以设置`@文档`到一个在其他方面有效但不包含所需属性的值,然后对其进行测试`@schema`.的输出`JSON_SCHEMA_VALIDATION_REPORT()`表明由于缺少必需的元素而导致验证失败,如下所示: ``` mysql> SET @document = '{}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document))\G *************************** 1. row *************************** JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document)): { "valid": false, "reason": "The JSON document location '#' failed requirement 'required' at JSON Schema location '#'", "schema-location": "#", "document-location": "#", "schema-failed-keyword": "required" } 1 row in set (0.00 sec) ``` 如果我们现在设置`@schema`到相同的 JSON 模式,但没有`必需的`属性,`@文档`验证,因为它是一个有效的 JSON 对象,即使它不包含任何属性,如下所示: ``` mysql> SET @schema = '{ '> "id": "http://json-schema.org/geo", '> "$schema": "http://json-schema.org/draft-04/schema#", '> "description": "A geographical coordinate", '> "type": "object", '> "properties": { '> "latitude": { '> "type": "number", '> "minimum": -90, '> "maximum": 90 '> }, '> "longitude": { '> "type": "number", '> "minimum": -180, '> "maximum": 180 '> } '> } '>}'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT JSON_SCHEMA_VALIDATION_REPORT(@schema, @document); +---------------------------------------------------+ | JSON_SCHEMA_VALIDATION_REPORT(@schema, @document) | +---------------------------------------------------+ | {"valid": true} | +---------------------------------------------------+ 1 row in set (0.00 sec) ```