MySQL文档存储快速入门指南
目录
一、MySQL文档存储说明
关系数据库(如MySQL)通常存储结构化数据,需要提前定义好数据的格式。而NoSQL的出现就是为了打破这种僵局,使得开发人员可以存储非结构化数据,使用文档的方式进行存储数据,无需提前定义数据格式。早先MariaDB也有对非结构化的数据进行存储的方案,称为dynamic column,但是方案是通过BLOB类型的方式来存储。这样导致的问题是查询性能不高,不能有效建立索引,与一些文档数据库对比,优势并不大,故在社区的反应证实比较一般。当然,MariaDB的dynamic column功能还不仅限于非结构化数据的存储。
MySQL 5.7.7版本开始,InnoDB存储引擎已经原生支持JSON格式,该格式不是简单的BLOB类似的替换。MySQL文档存储的出现消除了对单独的NoSQL文档数据库的需要,MySQL文档存储为无模式的JSON文档,提供了多文档事务支持和完整的ACID合规性。MySQL原生的JSON格式支持有以下的优势:
- JSON数据有效性检查:BLOB类型无法在数据库层做这样的约束性检查。
- 查询性能的提升:查询不需要遍历所有字符串才能找到数据。
- 支持索引:通过虚拟列的功能可以对JSON中的部分数据进行索引。
看一下官方摘取的文档存储架构图:
1)重点概念
1.1 Document
文档是由JSON对象表示的一组键和值对,通过JSON MySQL数据类型,使用MySQL二进制JSON对象在内部表示文档。字段的值可以包含其他文档,数组和文档列表。
{ "GNP": .6, "IndepYear": 1967, "Name": "Sealand", "_id": "SEA", "demographics": { "LifeExpectancy": 79, "Population": 27 }, "geography": { "Continent": "Europe", "Region": "British Islands", "SurfaceArea": 193 }, "government": { "GovernmentForm": "Monarchy", "HeadOfState": "Michael Bates" } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | { "GNP": .6, "IndepYear": 1967, "Name": "Sealand", "_id": "SEA", "demographics": { "LifeExpectancy": 79, "Population": 27 }, "geography": { "Continent": "Europe", "Region": "British Islands", "SurfaceArea": 193 }, "government": { "GovernmentForm": "Monarchy", "HeadOfState": "Michael Bates" } } |
1.2 Collection
Collection是一个容器,可以理解为关系型表,可用于将文档存储在MySQL数据库中。
2)CRUD操作
创建,读取,更新和删除(CRUD)操作是可以在数据库集合或表上执行的四个基本操作。关于MySQL这意味着:
- 创建一个新条目(插入或添加)
- 阅读条目(查询)
- 更新条目
- 删除条目
PS:如果你接触过MongoDB,那么文档和集合的概念对你来说就很容易理解了,MongoDB就是一个文档数据库。
3)X插件
使用X协议实现通信的MySQL服务器插件,支持实现X DevAPI的客户端,使您可以使用MySQL存储文档。
4)X协议
与运行X插件的MySQL服务器通信的协议,X协议支持CRUD和SQL操作,通过SASL的身份验证允许命令的流式传输(流水线),并且可以在协议和消息层上扩展。
二、MySQL X插件安装
本节介绍如何安装X插件,使MySQL Server能够使用X协议,并使用MySQL Shell作为服务器的客户端。
使用MySQL作为文档存储的先决条件是实现X协议的X插件。X插件随MySQL一起提供 – 安装它不涉及单独的下载。
将MySQL设置为文档存储,遵循以下步骤:
1)安装MySQL 8或从MySQL 5.7.12或更低版本升级
完成安装或升级后,启动服务器。
注意:MySQL安装程序使您能够同时执行此操作和下一步(安装X插件),以在Microsoft Windows上进行新的安装。在插件和扩展屏幕中,勾选启用X协议/ MySQL作为文档存储复选框。安装完成后,请确认X插件已安装。
2)安装X插件
- 使用MySQL Shell
需要先安装MySQL-shell工具,下面会介绍。
$ mysqlsh -u root -h localhost --classic --dba enableXProtocol
1 | $ mysqlsh -u root -h localhost --classic --dba enableXProtocol |
- 使用MySQL客户端
在Linux系统上,只要该MySQL帐户具有安装插件INSERT的特权mysql.plugin表即可。
mysql> INSTALL PLUGIN mysqlx SONAME 'mysqlx.so';
1 | mysql> INSTALL PLUGIN mysqlx SONAME 'mysqlx.so'; |
关于Windows系统自行看官方文档。
3)验证X插件是否已安装
- MySQL Shell命令
$ mysqlsh -u root -h localhost --sqlc -e "show plugins"
1 | $ mysqlsh -u root -h localhost --sqlc -e "show plugins" |
- MySQL客户端程序命令
$ mysql -u root -h localhost -p -e "show plugins"
1 | $ mysql -u root -h localhost -p -e "show plugins" |
4)mysqlxsys@localhost用户帐号
安装X插件创建一个 mysqlxsys@localhost
用户帐户。如果由于某种原因造成用户帐户失败,X插件安装也会失败。这是关于 mysqlxsys@localhost
用户帐户是什么以及创建失败时该做什么的说明。
X插件安装过程使用MySQL的root
用户为用户创建一个内部帐户 mysqlxsys@localhost
。该 mysqlxsys@localhost
帐户被X插件用于外部用户对MySQL帐户系统的身份验证,以及在特权用户请求时杀死会话。该mysqlxsys@localhost
帐户被创建为已锁定,因此不能用于外部用户登录。如果由于某些原因MySQL的root
帐户不可用,在开始X插件安装之前,您必须通过在mysql命令行客户端中发出以下语句来手动创建用户:
CREATE USER IF NOT EXISTS mysqlxsys@localhost IDENTIFIED WITH mysql_native_password AS 'password' ACCOUNT LOCK; GRANT SELECT ON mysql.user TO mysqlxsys@localhost; GRANT SUPER ON *.* TO mysqlxsys@localhost;
1 2 3 4 | CREATE USER IF NOT EXISTS mysqlxsys@localhost IDENTIFIED WITH mysql_native_password AS 'password' ACCOUNT LOCK; GRANT SELECT ON mysql.user TO mysqlxsys@localhost; GRANT SUPER ON *.* TO mysqlxsys@localhost; |
5)卸载X插件
如果您想要卸载(停用)X插件,请在mysql命令行客户机中发出以下语句:
mysql> UNINSTALL PLUGIN mysqlx;
1 | mysql> UNINSTALL PLUGIN mysqlx; |
此外,卸载插件会删除mysqlxsys用户。
更多关于X插件的使用指南看官方文档:X Plugin
三、MySQL Shell用户指南
1)MySQL Shell介绍
MySQL Shell是MySQL服务器的高级命令行客户端和代码编辑器。除了SQL之外,MySQL Shell还提供了JavaScript和Python的脚本功能。当MySQL Shell通过X协议连接到MySQL服务器时,X DevAPI可用于处理关系数据和文档数据。X插件是MySQL Server 5.7.12及更高版本的新的MySQL服务器功能,它使您能够使用X DevAPI对代码进行原型代码与运行X插件的MySQL服务器进行通信。
2)MySQL Shell功能
- 互动代码执行
MySQL Shell提供了一种交互式代码执行模式,您可以在MySQL Shell提示符下键入代码,并处理每个输入的语句,并将处理结果打印在屏幕上。
- 支持的语言
MySQL Shell处理以下语言的代码:JavaScript,Python和SQL。任何输入的代码根据当前活动的语言被处理为这些语言之一。还有一些特定的命令被视为 “ shell命令 ”,使您能够配置MySQL Shell或检索信息。
- 批次执行代码
除了代码的交互执行之外,MySQL Shell还可以从不同的来源获取代码并进行处理。这种以非交互方式处理代码的方法称为 批处理。
由于批量执行模式用于单一语言的脚本处理,因此限制为具有最小的非格式化输出并禁用命令的执行。为了避免这些限制,请使用--interactive
命令行选项,它可以告诉MySQL Shell执行输入,就像它是一个交互式会话一样。在这种模式下输入被处理一行一行就如同每一行是在交互会话类型。
- 输出格式
MySQL Shell根据使用方式提供不同格式的输出:Tabbed,Table和JSON。
- 多线支持
可以使用命令编写多行代码,使MySQL Shell能够缓存多行,然后作为单个语句执行它们。
- X协议支持
MySQL Shell旨在为支持X协议的所有MySQL产品提供集成的命令行客户端。MySQL Shell的开发特性专为使用X协议的会话而设计。MySQL Shell也可以连接到不支持使用旧版MySQL协议的X协议的MySQL服务器。来自X DevAPI的一小部分功能可用于使用旧版MySQL协议创建的会话。
3)MySQL Shell安装
MySQL Shell可用于Microsoft Windows,Linux和OS X,用于64位平台。MySQL Shell要求内置的X插件对于MySQL 5.7.12或更高版本是有效的。
$ yum install mysql-shell
1 | $ yum install mysql-shell |
或者手动下载mysql-shell的源码包或RPM包:下载MySQL Shell
4)MySQL Shell会话
MySQL Shell是通过脚本语言(如JavaScript或Python)来操作MySQL服务器的统一接口。为了保持与以前版本的兼容性,SQL也可以在某些模式下执行。需要连接到MySQL服务器。在MySQL Shell中,这些连接由Session对象处理 。
以下不同类型的Session对象可用:
- X Session:使用此会话类型进行新的应用程序开发。它提供与MySQL服务器的最佳集成,因此默认情况下使用它。SQL执行不受支持,因此与MySQL Shell的SQL模式不兼容。
- Node Session:在启用X协议的MySQL服务器上使用此会话类型进行SQL执行。SQL执行可用于此会话类型,因此可以在MySQL Shell的SQL模式中使用。只有当直接连接到启用X协议的MySQL服务器时,才能使用该会话类型 。
- Classic Session:使用此会话类型与未启用X协议的MySQL服务器进行交互。SQL执行可用于此会话类型,因此可以在MySQL Shell的SQL模式中使用。可用于此类型会话的开发API非常有限。例如,没有CRUD操作,不支持集合处理,并且不支持绑定。
默认情况下,MySQL Shell会创建一个XSession对象。要选择应该创建哪种类型的会话,请使用以下选项之一:
5)MySQL Shell连接
本节假设您有一个运行X Plugin的MySQL服务器,并且您已经安装了MySQL Shell,这两个部分都可以看前面章节。
MySQL Shell可以配置为使用命令行选项在启动时或从MySQL Shell本身连接到运行X Plugin的MySQL服务器。可以使用诸如用户,主机名和端口之类的各个参数或使用格式的统一资源标识符(URI)来指定MySQL服务器的地址user@host:port/schema,例如mike@myserver:33060/testDB。以下部分将介绍这些方法。
您需要一个帐户名和密码才能使用MySQL Shell建立会话。如果不为连接指定参数,则使用以下默认值:
- 用户默认为当前系统用户名。
- 主机默认为localhost。
- 端口在使用X会话时默认为X插件端口33060,当使用传统会话时默认为端口3306。
使用X协议的MySQL Shell连接总是使用TCP,不支持使用Linux套接字。使用MySQL协议的MySQL Shell连接可以通过指定--socket
命令行选项来使用Linux套接字 。
5.1 使用URI字符串进行连接
您可以使用--uri
命令行选项通过传递串行格式的连接数据来配置MySQL Shell连接到的MySQL服务器 。
[ dbuser[:[ dbpassword]] @] host[:port] [/ schema]
1 | [ dbuser[:[ dbpassword]] @] host[:port] [/ schema] |
这些选项的描述:
dbuser
:指定要用于身份验证过程的MySQL用户帐户。dbpassword
:指定要用于身份验证过程的dbuser密码。host
:指定会话对象连接到的主机。如果未指定, 则默认使用localhost。port
:指定目标MySQL服务器正在侦听连接的端口。如果未指定,则默认情况下,对于启用了X协议的会话使用33060,而3306是传统MySQL协议会话的默认值。schema
:表示建立会话时要设置为默认的数据库。
如果没有使用URI指定密码(建议使用),则会提示输入密码。
连接X会话(默认)
$ mysqlsh --uri user@localhost
1 | $ mysqlsh --uri user@localhost |
连接节点会话(端口33060)
$ mysqlsh --uri user@localhost:33060 --node
1 | $ mysqlsh --uri user@localhost:33060 --node |
连接经典会话
$ mysqlsh --uri user@localhost:3306 --classic
1 | $ mysqlsh --uri user@localhost:3306 --classic |
虽然不建议使用无密码帐号,但您可以:
在用户名后面指定一个没有密码 的用户,例如:
$ mysqlsh --uri user@localhost
1 | $ mysqlsh --uri user@localhost |
除了手动指定URI之外,还可以使用存储的会话。
在服务器实例运行的同一系统上,打开一个终端窗口,并使用以下命令启动MySQL Shell:
$ mysqlsh root@localhost/schema $ mysqlsh mysqlx://root@some.server:33060/world_x $ mysqlsh --uri root@localhost --py -f sample.py sample param $ mysqlsh root@targethost:33060 -s world_x -f sample.js
1 2 3 4 | $ mysqlsh root@localhost/schema $ mysqlsh mysqlx://root@some.server:33060/world_x $ mysqlsh --uri root@localhost --py -f sample.py sample param $ mysqlsh root@targethost:33060 -s world_x -f sample.js |
mysql-sehll提供了以上几种连接方式,下面演示mysql-shell,并切换到sql模式(默认是js模式)。
$ mysqlsh --uri root:@localhost Creating a Session to 'root@localhost' Node Session successfully established. No default schema selected. Welcome to MySQL Shell 1.0.9 .................... Type '\help', '\h' or '\?' for help, type '\quit' or '\q' to exit. Currently in JavaScript mode. Use \sql to switch to SQL mode and execute queries. mysql-js> \sql Switching to SQL mode... Commands end with ; mysql-sql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | test | | world_x | +--------------------+ 6 rows in set (0.00 sec)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | $ mysqlsh --uri root:@localhost Creating a Session to 'root@localhost' Node Session successfully established. No default schema selected. Welcome to MySQL Shell 1.0.9 .................... Type '\help', '\h' or '\?' for help, type '\quit' or '\q' to exit. Currently in JavaScript mode. Use \sql to switch to SQL mode and execute queries. mysql-js> \sql Switching to SQL mode... Commands end with ; mysql-sql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | test | | world_x | +--------------------+ 6 rows in set (0.00 sec) |
5.2 使用Shell命令创建会话
如果您在未指定连接参数的情况下打开MySQL Shell,则MySQL Shell将在没有建立的全局会话的情况下打开。一旦使用以下Shell命令启动MySQL Shell即可建立全局会话 :
\connect URI
:创建XSession。\connect -n URI
:创建节点会话。\connect -c URI
:创建一个经典会话。
使用URI参数配置连接,该参数遵循与--uri
命令行选项相同的语法。例如:
$ mysqlsh mysql-js> \connect root@localhost Creating a Session to 'root@localhost' Enter password: Classic Session successfully established. No default schema selected. mysql-js>
1 2 3 4 5 6 | $ mysqlsh mysql-js> \connect root@localhost Creating a Session to 'root@localhost' Enter password: Classic Session successfully established. No default schema selected. mysql-js> |
6)MySQL Shell全局变量
MySQL Shell将某些变量保留为全局变量,它们分配给脚本中常用的对象。本节介绍可用的全局变量,并提供使用它们的示例。全局变量为:
session
代表全局会话,如果已经建立。db
如果已经定义了一个模式,例如通过一个URI定义了一个模式。
MySQL Shell提供了与使用全局变量相关的常见情况的交互式错误解决方案。例如:
- 尝试使用未定义的
session
全局变量。 - 尝试使用不存在的模式检索
session
。 - 尝试使用未定义的
db
全局变量。
6.1 未定义的全局会话
全局session
变量在建立全局会话时设置。当建立全局会话时,session
在MySQL Shell中发出语句会显示会话类型及其URI,如下所示:
mysql-js> session <XSession:root@localhost:33060> mysql-js>
1 2 3 | mysql-js> session <XSession:root@localhost:33060> mysql-js> |
如果没有建立全局会话,MySQL Shell会显示以下内容:
mysql-js> session <Undefined> mysql-js>
1 2 3 | mysql-js> session <Undefined> mysql-js> |
6.2 未定义的db变量
全局db
变量在建立全局会话并配置默认模式时设置。例如,使用诸如在端口33060上建立连接 root@localhost/world_x
到MySQL服务器的全局会话作为用户的URI将模式分配给全局变量 。一旦定义了一个模式,在MySQL Shell提示符下发出如下的模式名称:
mysql-js> db <Schema:world_x> mysql-js>
1 2 3 | mysql-js> db <Schema:world_x> mysql-js> |
如果没有建立全局会话,将显示以下内容:
mysql-js> db <Undefined> mysql-js>
1 2 3 | mysql-js> db <Undefined> mysql-js> |
如果db
在没有建立全局会话时尝试使用变量,则会显示以下错误:
mysql-js> db.getCollections() LogicError: The db variable is not set, establish a global session first. at (shell):1:2 in db.getCollections() ^
1 2 3 4 5 | mysql-js> db.getCollections() LogicError: The db variable is not set, establish a global session first. at (shell):1:2 in db.getCollections() ^ |
如果已建立全局会话,但尝试使用未定义的db
交互式错误解决,并提示您通过提供模式名称来定义活动模式。如果这样成功,则将 db
变量设置为定义的模式。例如:
mysql-js> db.getCollections() The db variable is not set, do you want to set the active schema? [y/N]:y Please specify the schema:world_x [ <Collection:countryinfo> ] mysql-js> db <Schema:world_x> mysql-js>
1 2 3 4 5 6 7 8 9 | mysql-js> db.getCollections() The db variable is not set, do you want to set the active schema? [y/N]:y Please specify the schema:world_x [ <Collection:countryinfo> ] mysql-js> db <Schema:world_x> mysql-js> |
7)MySQL Shell命令
MySQL Shell提供的命令使您可以修改代码编辑器的执行环境,例如配置当前编程语言或MySQL服务器连接。下表列出了可用的命令,无论当前选择的语言如何。由于命令需要独立于执行模式可用,所以它们以转义序列(\
字符)开头。
\help:打印有关MySQL Shell命令的帮助。
\quit:退出MySQL Shell。
\:在SQL模式下,开始多行模式。当输入空行时,代码被缓存并执行。
\status:显示当前的MySQL Shell状态。
\js:将执行模式切换为JavaScript。
\py:将执行模式切换为Python。
\sql:将执行模式切换到SQL。
\connect:使用XSession(X协议)连接到具有URI的MySQL服务器。
\use:指定要使用的模式。
\source.:使用活动语言执行脚本文件。
\warnings:显示语句生成的任何警告。
\nowarnings:不显示语句生成的任何警告。
\lsconn:打印存储会话的连接数据。
\saveconn:保存会话的连接数据, -f可以强制覆盖现有连接。
\rmconn:删除存储的会话。
8)MySQL Shell会话存储
本节介绍如何通过会话名称标识MySQL Shell存储会话连接数据的持久列表。
管理和使用存储的连接数据有两种方法:
- 通过MySQL Shell命令。
- 通过可用于JavaScript和Python的内置对象。
使用这些选项,您可以添加,更新,删除,列出和使用存储的连接数据。
这些连接作为文本文件存储在MySQL Shell文件夹中,通常位于用户目录中,文件名是stored_sessions.json
9)MySQL Shell for Javascript
9.1 导入示例数据库
要准备world_x
数据库示例,下载world_x-db.zip并导入。
$ wget http://downloads.mysql.com/docs/world_x-db.zip $ unzip world_x-db.zip $ mysqlsh -u root --sql < world_x-db/world_x.sql Enter password: Records: 4079 Duplicates: 0 Warnings: 0 Records: 239 Duplicates: 0 Warnings: 0 Records: 239 Duplicates: 0 Warnings: 0 Records: 984 Duplicates: 0 Warnings: 0
1 2 3 4 5 6 7 8 | $ wget http://downloads.mysql.com/docs/world_x-db.zip $ unzip world_x-db.zip $ mysqlsh -u root --sql < world_x-db/world_x.sql Enter password: Records: 4079 Duplicates: 0 Warnings: 0 Records: 239 Duplicates: 0 Warnings: 0 Records: 239 Duplicates: 0 Warnings: 0 Records: 984 Duplicates: 0 Warnings: 0 |
该world_x
数据库样本包含一个JSON Collection和一组三个关系表:
mysql-sql> use world_x; Query OK, 0 rows affected (0.00 sec) mysql-sql> show tables; +-------------------+ | Tables_in_world_x | +-------------------+ | city | | country | | countryinfo | | countrylanguage | +-------------------+ 4 rows in set (0.00 sec)
1 2 3 4 5 6 7 8 9 10 11 12 | mysql-sql> use world_x; Query OK, 0 rows affected (0.00 sec) mysql-sql> show tables; +-------------------+ | Tables_in_world_x | +-------------------+ | city | | country | | countryinfo | | countrylanguage | +-------------------+ 4 rows in set (0.00 sec) |
表和集合
- Collection
- countryinfo:关于世界各国的信息。
mysql-sql> desc countryinfo; +-------+-------------+------+-----+---------+------------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+------------------+ | doc | json | YES | | null | | | _id | varchar(32) | NO | PRI | null | STORED GENERATED | +-------+-------------+------+-----+---------+------------------+ 2 rows in set (0.00 sec)
1
2
3
4
5
6
7
8
mysql-sql> desc countryinfo;
+-------+-------------+------+-----+---------+------------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+------------------+
| doc | json | YES | | null | |
| _id | varchar(32) | NO | PRI | null | STORED GENERATED |
+-------+-------------+------+-----+---------+------------------+
2 rows in set (0.00 sec)
- Tables
- country:关于世界各国的基本信息。
mysql-sql> desc country; +---------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+----------+------+-----+---------+-------+ | Code | char(3) | NO | PRI | | | | Name | char(52) | NO | | | | | Capital | int(11) | YES | | null | | | Code2 | char(2) | NO | | | | +---------+----------+------+-----+---------+-------+ 4 rows in set (0.00 sec)
1
2
3
4
5
6
7
8
9
10
mysql-sql> desc country;
+---------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+----------+------+-----+---------+-------+
| Code | char(3) | NO | PRI | | |
| Name | char(52) | NO | | | |
| Capital | int(11) | YES | | null | |
| Code2 | char(2) | NO | | | |
+---------+----------+------+-----+---------+-------+
4 rows in set (0.00 sec)
- city:这些国家的一些城市的信息。
mysql-sql> desc city; +-------------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+----------+------+-----+---------+----------------+ | ID | int(11) | NO | PRI | null | auto_increment | | Name | char(35) | NO | | | | | CountryCode | char(3) | NO | | | | | District | char(20) | NO | | | | | Info | json | YES | | null | | +-------------+----------+------+-----+---------+----------------+ 5 rows in set (0.00 sec)
1
2
3
4
5
6
7
8
9
10
11
mysql-sql> desc city;
+-------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | null | auto_increment |
| Name | char(35) | NO | | | |
| CountryCode | char(3) | NO | | | |
| District | char(20) | NO | | | |
| Info | json | YES | | null | |
+-------------+----------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
- countrylanguage:每个国家使用的语言。
mysql-sql> desc countrylanguage; +-------------+---------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------+---------------+------+-----+---------+-------+ | CountryCode | char(3) | NO | PRI | | | | Language | char(30) | NO | PRI | | | | IsOfficial | enum('T','F') | NO | | F | | | Percentage | float(4,1) | NO | | 0.0 | | +-------------+---------------+------+-----+---------+-------+ 4 rows in set (0.00 sec)
1
2
3
4
5
6
7
8
9
10
mysql-sql> desc countrylanguage;
+-------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------+------+-----+---------+-------+
| CountryCode | char(3) | NO | PRI | | |
| Language | char(30) | NO | PRI | | |
| IsOfficial | enum('T','F') | NO | | F | |
| Percentage | float(4,1) | NO | | 0.0 | |
+-------------+---------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
9.2 启动MySQL Shell
安装并启动MySQL服务器后,将MySQL Shell连接到服务器实例。默认情况下,MySQL Shell使用X协议连接。
在服务器实例运行的同一系统上,打开一个终端窗口并使用以下命令启动MySQL Shell:
$ mysqlsh root@localhost/world_x Creating a Session to 'root@localhost/world_x' Enter password: mysql-js>
1 2 3 4 | $ mysqlsh root@localhost/world_x Creating a Session to 'root@localhost/world_x' Enter password: mysql-js> |
此外:
root
代表您的MySQL帐户的用户名。- MySQL Shell提示您输入密码。
- 此会话的默认模式是
world_x
数据库。 - 该
mysql-js>
提示表示此会话的活动语言是JavaScript。
9.3 获取MySQL Shell的帮助
在命令解释器的提示符下 输入mysqlsh –help以获取命令行选项列表。
$ mysqlsh --help
1 | $ mysqlsh --help |
在MySQL Shell提示符下键入\ help以获取可用命令及其说明的列表。
mysql-js> \help
1 | mysql-js> \help |
键入\ help后跟命令名,以获取有关单个MySQL Shell命令的详细帮助。例如,要查看\ connect命令的帮助,请键入:
mysql-js> \help \connect
1 | mysql-js> \help \connect |
9.4 退出MySQL Shell
要退出MySQL Shell,请键入以下命令:
mysql-js> \quit
1 | mysql-js> \quit |
9.5 文档和集合操作(CURD)
在MySQL中,集合包含可以添加,查找,更新和删除的JSON文档。集合是你创建,本节中的示例使用world_x
数据库中的countryinfo集合 。
在MySQL中,文档被表示为JSON对象。在内部,它们以高效的二进制格式存储,可以快速查找和更新。
简单的JavaScript文档格式:
{field1: "value", field2 : 10, "field 3": null}
1 | {field1: "value", field2 : 10, "field 3": null} |
简单的JavaScript文档数组:
[{Name: "Aruba", _id: "ABW"}, {Name: "Angola", _id: "AGO"}]
1 | [{Name: "Aruba", _id: "ABW"}, {Name: "Angola", _id: "AGO"}] |
MySQL支持JSON文档中的以下JavaScript值类型:
- 数字(整数和浮点数)
- 字符串
- 布尔值(false和true)
- 空值
- 数组或更多的JSON值
- 嵌套(或嵌入)更多JSON值的对象
集合相当于一个容器,跟关系表类似,用于共享多个索引的文档。每个集合都有唯一的名称,并且存在于单个库中。
9.5.1 创建、列出和删除集合
在MySQL Shell中,您可以创建新集合,获取模式中现有集合的列表,并从模式中删除现有集合。集合名称区分大小写,每个集合名称必须是唯一的。
确认模式
要显示分配给模式变量的值,请键入db
。
$ mysqlsh --uri root@localhost mysql-js> db <Undefined>
1 2 3 | $ mysqlsh --uri root@localhost mysql-js> db <Undefined> |
如果模式值不是Schema:world_x
,db
则按如下所示设置变量:
mysql-js> \use world_x Schema set to `world_x`. mysql-js> db <Schema:world_x>
1 2 3 4 | mysql-js> \use world_x Schema set to `world_x`. mysql-js> db <Schema:world_x> |
创建一个集合
要在现有模式中创建新集合,请使用该 createCollection()
方法。
以下示例在world_x
数据库中创建 一个名为flags的集合。该方法返回一个集合对象。
mysql-js> db.createCollection("flags") <Collection:flags>
1 2 | mysql-js> db.createCollection("flags") <Collection:flags> |
列表所有集合
要显示world_x
数据库中的所有集合,请使用getCollections()
模式对象上的方法。服务器返回的集合将显示在括号之间。
mysql-js> db.getCollections() [ <Collection:countryinfo>, <Collection:flags> ]
1 2 3 4 5 | mysql-js> db.getCollections() [ <Collection:countryinfo>, <Collection:flags> ] |
删除一个集合
要从数据库中删除现有集合,请使用 dropCollection()
会话对象上的方法。例如,要从world_x
数据库中删除flags集合 ,请键入:
mysql-js> session.dropCollection("world_x", "flags")
1 | mysql-js> session.dropCollection("world_x", "flags") |
9.5.2 添加文档
您可以使用该add()
方法将一个文档或列表文档插入到使用MySQL Shell的现有集合中。本节中的所有示例都使用countryinfo集合,将以下文档插入countryinfo集合。按两次Enter键插入文档。
mysql-js> db.countryinfo.add( { GNP: .6, IndepYear: 1967, Name: "Sealand", _id: "SEA", demographics: { LifeExpectancy: 79, Population: 27 }, geography: { Continent: "Europe", Region: "British Islands", SurfaceArea: 193 }, government: { GovernmentForm: "Monarchy", HeadOfState: "Michael Bates" } } )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | mysql-js> db.countryinfo.add( { GNP: .6, IndepYear: 1967, Name: "Sealand", _id: "SEA", demographics: { LifeExpectancy: 79, Population: 27 }, geography: { Continent: "Europe", Region: "British Islands", SurfaceArea: 193 }, government: { GovernmentForm: "Monarchy", HeadOfState: "Michael Bates" } } ) |
该方法返回操作的状态。
每个文档都需要一个标识符字段 _id
。该_id
字段的值 在同一集合中的所有文档中必须是唯一的。如果传递给该add()
方法的文档不包含该 _id
字段,则MySQL Shell会自动将一个字段插入到文档中,并将该值设置为生成的通用唯一标识符(UUID)。
9.5.3 查找文档
您可以使用该find()
方法从数据库中的集合查询和返回文档。MySQL Shell提供了使用该 find()
方法的其他方法来过滤和排序返回的文档。
MySQL提供以下操作符来指定搜索条件:OR (||), AND (&&), XOR, IS, NOT, BETWEEN, IN, LIKE, !=, <>, >, >=, <, <=, &, |, <<, >>, +, –, *, /, ~, and %。
查找集合中的所有文档
要返回集合中的所有文档,请使用该 find()
方法而不指定搜索条件。例如,以下操作将返回countryinfo集合中的所有文档。
mysql-js> db.countryinfo.find() [ { "GNP": 828, "IndepYear": null, "Name": "Aruba", "_id": "ABW", "demographics": { "LifeExpectancy": 78.4000015258789, "Population": 103000 }, "geography": { "Continent": "North America", "Region": "Caribbean", "SurfaceArea": 193 }, "government": { "GovernmentForm": "Nonmetropolitan Territory of The Netherlands", "HeadOfState": "Beatrix" } ... } ] 240 documents in set (0.00 sec)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | mysql-js> db.countryinfo.find() [ { "GNP": 828, "IndepYear": null, "Name": "Aruba", "_id": "ABW", "demographics": { "LifeExpectancy": 78.4000015258789, "Population": 103000 }, "geography": { "Continent": "North America", "Region": "Caribbean", "SurfaceArea": 193 }, "government": { "GovernmentForm": "Nonmetropolitan Territory of The Netherlands", "HeadOfState": "Beatrix" } ... } ] 240 documents in set (0.00 sec) |
过滤搜索
您可以使用该find()
方法包含搜索条件 。形成搜索条件的表达式的语法与传统MySQL的语法相同。您必须用引号括起所有表达式。
本节中的所有示例都使用world_x
数据库中的countryinfo集合。为了简洁起见,有些示例不显示输出。
简单的搜索条件由_id
文档的字段和唯一标识符组成。以下示例返回与标识符字符串匹配的单个文档:
mysql-js> db.countryinfo.find("_id = 'ABW'")
1 | mysql-js> db.countryinfo.find("_id = 'ABW'") |
以下示例搜索所有国民生产总值高于5000亿美元的国家。国家信息收集措施以百万为单位,以国民生产总值为单位。
mysql-js> db.countryinfo.find("GNP > 500000")
1 | mysql-js> db.countryinfo.find("GNP > 500000") |
以下查询中的人口字段嵌入到人口统计对象中。要访问嵌入式字段,请使用人口统计信息和“人口”之间的时间段来标识关系。文档和字段名称区分大小写。
mysql-js> db.countryinfo.find("GNP > 500000 and demographics.Population < 100000000")
1 | mysql-js> db.countryinfo.find("GNP > 500000 and demographics.Population < 100000000") |
以下表达式中的算术运算符用于查询人均国民生产总值高于3万美元的国家。搜索条件可以包括算术运算符和大多数MySQL函数。
mysql-js> db.countryinfo.find("GNP*1000000/demographics.Population > 30000")
1 | mysql-js> db.countryinfo.find("GNP*1000000/demographics.Population > 30000") |
对象返回
您可以返回文档的特定字段,而不是返回所有字段。以下示例返回与搜索条件匹配的countryinfo集合中的所有文档的GNP和Name字段。
使用该fields()
方法传递要返回的字段列表。
mysql-js> db.countryinfo.find("GNP > 5000000").fields(["GNP", "Name"])
1 | mysql-js> db.countryinfo.find("GNP > 5000000").fields(["GNP", "Name"]) |
限制,排序和跳过结果
您可以应用limit()
, sort()
和skip()
方法来管理由返回文档的数量和顺序find()
的方法。
要指定结果集中包含的文档数量,请将limit()
方法附加到find()
方法中。以下查询返回countryinfo集合中的前五个文档。
mysql-js> db.countryinfo.find().limit(5)
1 | mysql-js> db.countryinfo.find().limit(5) |
要为结果指定一个顺序,请将该sort()
方法附加 到该 find()
方法。sort()
根据需要将一个或多个字段的列表传递给 方法,以及可选的descending(desc
)或ascending(asc
)属性。升序是默认的订单类型。
例如,以下查询会通过IndepYear字段排序所有文档,然后按降序返回前八个文档。
mysql-js> db.countryinfo.find().sort(["IndepYear desc"]).limit(8)
1 | mysql-js> db.countryinfo.find().sort(["IndepYear desc"]).limit(8) |
默认情况下,该limit()
方法从集合中的第一个文档开始。您可以使用该 skip()
方法更改起始文档。例如,要忽略第一个文档并返回与条件匹配的下一个8个文档,则传递给该 skip()
方法的值为1。
mysql-js> db.countryinfo.find().sort(["IndepYear desc"]).limit(8).skip(1)
1 | mysql-js> db.countryinfo.find().sort(["IndepYear desc"]).limit(8).skip(1) |
9.5.4 修改文档
您可以使用该modify()
方法来更新集合中的一个或多个文档。X DevAPI提供了与方法一起使用的其他modify()
方法:
- 在文档中设置和取消设置字段。
- 追加,插入和删除数组。
- 绑定,限制和排序要修改的文档。
设置和取消设置字段
该modify()
方法通过过滤集合以仅包括要修改的文档,然后将您指定的操作应用于这些文档。
在以下示例中,该modify()
方法使用搜索条件来标识要更改的文档,然后该set()
方法将替换嵌套的人口统计对象中的两个值。
mysql-js> db.countryinfo.modify("_id = 'SEA'").set("demographics", {LifeExpectancy: 78, Population: 28})
1 | mysql-js> db.countryinfo.modify("_id = 'SEA'").set("demographics", {LifeExpectancy: 78, Population: 28}) |
修改文档后,使用该find()
方法验证更改。
要从文档中删除内容,请使用 modify()
和unset()
方法。例如,以下查询从符合搜索条件的文档中删除GNP。
mysql-js> db.countryinfo.modify("Name = 'Sealand'").unset("GNP")
1 | mysql-js> db.countryinfo.modify("Name = 'Sealand'").unset("GNP") |
使用该find()
方法验证更改。
mysql-js> db.countryinfo.find("Name = 'Sealand'")
1 | mysql-js> db.countryinfo.find("Name = 'Sealand'") |
9.5.5 删除文档
您可以使用该remove()
方法从数据库中的集合中删除一些或所有文档。X DevAPI提供了用于该 remove()
方法的其他方法来过滤和排序要删除的文档。
使用条件删除文档
以下示例将搜索条件传递给remove()
方法。所有符合条件的文件将从countryinfo集合中删除。在此示例中,一个文档与条件匹配。
mysql-js> db.countryinfo.remove("_id = 'SEA'")
1 | mysql-js> db.countryinfo.remove("_id = 'SEA'") |
删除第一个文档
要删除countryinfo集合中的第一个文档,请使用limit()
值为1 的方法。
mysql-js> db.countryinfo.remove().limit(1)
1 | mysql-js> db.countryinfo.remove().limit(1) |
删除订单中的最后一个文档
以下示例按国家名称删除countryinfo集合中的最后一个文档。
mysql-js> db.countryinfo.remove().sort(["Name desc"]).limit(1)
1 | mysql-js> db.countryinfo.remove().sort(["Name desc"]).limit(1) |
删除集合中的所有文档
您可以删除集合中的所有文档。为此,请使用该remove()
方法而不指定搜索条件。
mysql-js> db.countryinfo.remove()
1 | mysql-js> db.countryinfo.remove() |
9.5.6 创建和删除索引
索引用于快速查找具有特定字段值的文档。没有索引,MySQL必须从第一个文档开始,然后阅读整个集合来查找相关的字段。集合越大,成本越高。如果集合很大,并且在特定字段上的查询是常见的,那么请考虑在文档中的特定字段上创建索引。
例如,以下查询将使用索引执行得更好:
mysql-js> db.countryinfo.find("demographics.Population < 100")
1 | mysql-js> db.countryinfo.find("demographics.Population < 100") |
该createIndex()
方法创建一个可以定义为非唯一或唯一的索引。使用该 field()
方法链接应编入索引的字段。execute()
创建或删除索引需要该方法。
在MySQL中,_id
默认情况下该字段相当于主键。
添加非唯一索引
要创建一个非唯一索引,请传递该 createIndex()
方法一个索引名称。重复的索引名称被禁止。
在下面的示例中,该field()
方法的第一个参数指定 了人口统计对象中的“人口”字段,下一个参数表示该字段应该作为整数数值进行索引。最后一个参数指示该字段是否需要NOT NULL约束。如果值为 false
,则该字段可以包含 NULL
值。
mysql-js> db.countryinfo.createIndex("pop").field("demographics.Population", "INTEGER", false).execute()
1 | mysql-js> db.countryinfo.createIndex("pop").field("demographics.Population", "INTEGER", false).execute() |
添加唯一索引
要创建唯一的索引,请传递 createIndex()
方法索引名称和 mysqlx.IndexType.UNIQUE
类型。国家 "Name"
是countryinfo收集索引中的另一个常见字段。在以下示例中,"Text(40)"
表示要索引的字符数,并true
指示该字段不能包含任何NULL
值。
mysql-js> db.countryinfo.createIndex("name", mysqlx.IndexType.UNIQUE).
1 | mysql-js> db.countryinfo.createIndex("name", mysqlx.IndexType.UNIQUE). |
删除索引
要删除索引,请将该索引dropIndex()
的名称传递给该方法。例如,您可以按如下所示删除“ pop ”索引:
mysql-js> db.countryinfo.dropIndex("pop").execute()
1 | mysql-js> db.countryinfo.dropIndex("pop").execute() |
9.6 关系表操作
你可以使用MySQL Shell来操作JSON文档,还可以操作关系表。
9.6.1 显示所有表
要在world_x
数据库中显示所有关系表,请使用getTables()
模式对象上的方法。
mysql-js> db.getTables()
1 | mysql-js> db.getTables() |
9.6.2 将记录插入到表中
你可以使用该insert()方法使用该values()方法将记录插入到现有关系表中。该insert()方法接受表中的单个列或所有列。使用一个或多个values()方法来指定要插入的值。
插入一个完整的记录
要插入完整的记录,请传递给insert()
方法表中的所有列。然后将values()
表中的每一列传递给方法一个值。例如,要向world_x
数据库中的city表添加新记录,请插入以下记录,然后按Enter键两次。
mysql-js> db.city.insert("ID", "Name", "CountryCode", "District", "Info"). values(null, "Olympia", "USA", "Washington", '{"Population": 5000}')
1 2 | mysql-js> db.city.insert("ID", "Name", "CountryCode", "District", "Info"). values(null, "Olympia", "USA", "Washington", '{"Population": 5000}') |
城市表有五列:ID,Name,CountryCode,District和Info。每个值必须与其所表示的列的数据类型相匹配。
插入部分记录
以下示例将值插入到城市表的ID,Name和CountryCode列中。
mysql-js> db.city.insert("ID", "Name", "CountryCode"). values(null, "Little Falls", "USA").values(null, "Happy Valley", "USA")
1 2 | mysql-js> db.city.insert("ID", "Name", "CountryCode"). values(null, "Little Falls", "USA").values(null, "Happy Valley", "USA") |
当使用该insert()
方法指定列时,值的数量必须与列数匹配。在上一个示例中,您必须提供三个值以匹配指定的三列。
9.6.3 查找表
您可以使用该select()
方法从数据库中的表查询和返回记录。X DevAPI提供了与方法一起使用的其他select()
方法来过滤和排序返回的记录。
MySQL提供以下操作符来指定搜索条件:OR (||), AND (&&), XOR, IS, NOT, BETWEEN, IN, LIKE, !=, <>, >, >=, <, <=, &, |, <<, >>, +, –, *, /, ~, and %.
选择所有记录
要发出从现有表返回所有记录的查询,请使用该select()
方法而不指定搜索条件。以下示例从world_x
数据库中的城市表中选择所有记录 。
mysql-js> db.city.select()
1 | mysql-js> db.city.select() |
过滤搜索
要发出返回一组表列的查询,请使用该select()
方法并指定列在方括号之间返回。此查询返回City表中的Name和CountryCode列。
mysql-js> db.city.select(["Name", "CountryCode"])
1 | mysql-js> db.city.select(["Name", "CountryCode"]) |
要发出返回与特定搜索条件匹配的行的查询,请使用该where()
方法来包括这些条件。例如,以下示例返回以字母Z开头的城市的名称和国家/地区代码。
mysql-js> db.city.select(["Name", "CountryCode"]).where("Name like 'Z%'")
1 | mysql-js> db.city.select(["Name", "CountryCode"]).where("Name like 'Z%'") |
您可以使用该bind()
方法将值与搜索条件分开。例如,替换“Name =’Z%’”作为条件,替换由冒号组成的命名占位符,后跟以字母开头的名称(如名称)。然后在bind()
方法中包括占位符和值 ,如下所示:
mysql-js> db.city.select(["Name", "CountryCode"]).where("Name like :name").bind("name", "Z%")
1 | mysql-js> db.city.select(["Name", "CountryCode"]).where("Name like :name").bind("name", "Z%") |
要使用AND
运算符发出查询,请在where()
方法的搜索条件之间添加运算符 。
mysql-js> db.city.select(["Name", "CountryCode"]).where("Name like 'Z%' and CountryCode = 'CHN'")
1 | mysql-js> db.city.select(["Name", "CountryCode"]).where("Name like 'Z%' and CountryCode = 'CHN'") |
要指定多个条件运算符,可以将括号中的搜索条件括起来以更改运算符优先级。以下示例演示了放置AND
和操作 OR
符。
mysql-js> db.city.select(["Name", "CountryCode"]).where("Name like 'Z%' and (CountryCode = 'CHN' or CountryCode = 'RUS')")
1 | mysql-js> db.city.select(["Name", "CountryCode"]).where("Name like 'Z%' and (CountryCode = 'CHN' or CountryCode = 'RUS')") |
限制,订单和偏移结果
您可以应用limit()
, orderBy()
和offSet()
方法来管理由返回的记录的数量和顺序select()
的方法。
要指定结果集中包含的记录数,请将limit()
方法附加到select()
方法中。例如,以下查询返回国家表中的前五个记录。
mysql-js> db.country.select(["Code", "Name"]).limit(5)
1 | mysql-js> db.country.select(["Code", "Name"]).limit(5) |
要为结果指定一个顺序,请将该orderBy()
方法附加 到该 select()
方法。orderBy()
根据需要,将一个或多个列的列表传递给 方法,以及可选的descending(desc
)或ascending(asc
)属性。升序是默认的订单类型。
例如,以下查询通过“名称”列排序所有记录,然后以降序返回前三个记录。
mysql-js> db.country.select(["Code", "Name"]).orderBy(["Name desc"]).limit(3)
1 | mysql-js> db.country.select(["Code", "Name"]).orderBy(["Name desc"]).limit(3) |
默认情况下,该limit()
方法从表中的第一条记录开始。您可以使用该 offset()
方法更改起始记录。例如,要忽略第一条记录并返回与条件匹配的下一个三条记录,请传递给 offset()
方法1的值。
mysql-js> db.country.select(["Code", "Name"]).orderBy(["Name desc"]).limit(3).offset(1)
1 | mysql-js> db.country.select(["Code", "Name"]).orderBy(["Name desc"]).limit(3).offset(1) |
9.6.4 更新表
您可以使用该update()
方法修改表中的一个或多个记录。该update()
方法通过过滤查询以仅包括要更新的记录,然后将您指定的操作应用于这些记录。
要更换城市名称中的城市名称,请将set()
方法传递给 新的城市名称。然后,传递where()
方法的城市名称来定位和替换。以下例子将北京城市与北京取而代之。
mysql-js> db.city.update().set("Name", "Beijing").where("Name = 'Peking'")
1 | mysql-js> db.city.update().set("Name", "Beijing").where("Name = 'Peking'") |
使用该select()
方法验证更改。
mysql-js> db.city.select(["ID", "Name", "CountryCode", "District", "Info"]).where("Name = 'Beijing'")
1 | mysql-js> db.city.select(["ID", "Name", "CountryCode", "District", "Info"]).where("Name = 'Beijing'") |
9.6.5 删除表
您可以使用该delete()
方法从数据库中的表中删除一些或所有记录。X DevAPI提供了与该方法一起使用的其他 delete()
方法来过滤和排序要删除的记录。
使用条件删除记录
以下示例将搜索条件传递给该 delete()
方法。所有符合条件的记录将从城市表中删除。在此示例中,一条记录与条件匹配。
mysql-js> db.city.delete().where("Name = 'Olympia'")
1 | mysql-js> db.city.delete().where("Name = 'Olympia'") |
删除第一个记录
要删除城市表中的第一条记录,请使用limit()
值为1的方法。
mysql-js> db.city.delete().limit(1)
1 | mysql-js> db.city.delete().limit(1) |
删除表中的所有记录
您可以删除表中的所有记录。为此,请使用该 delete()
方法而不指定搜索条件。
<官方文档>