第3章

Python操作数据库




数据库作为重要的基础软件之一,在现代软件开发中有着广泛的应用,特别是对于数字资产的存储、分发、管理,有着非常重要的作用。数据库是指长期存储在计算机内的、有组织的、可共享的数据的集合。通俗地讲,数据库就是专门存储并管理数据的地方。
数据库分为关系数据库与非关系数据库。关系数据库是采用关系模型来组织数据的数据库,即从一个数据可以关联并查询到其他相关联的很多数据。关系数据库的特点是对数据的一致性要求比较高,也就是对事务的支持。关系数据库多用于逻辑关联性较高的场景中,例如各类管理系统、电子商务平台、网上银行、网络支付等应用。其典型的代表是PostgreSQL数据库、MySQL数据库、Oracle数据库、MS SQL Server等。关系数据库因为数据的相关性,以及结构相对固定,所以关系数据库在面对大数据的情况下性能会有所欠缺。
非关系数据库又称为NoSQL,最常见的解释是nonrelational,即非关系,Not Only SQL也被很多人接受。非关系数据库的特点是易扩展、高性能。数据之间没有关系,所以就非常容易扩展。无形间在架构层面上带来了较强的扩展能力。非关系数据库因为数据结构的简单及数据间的无关性,使非关系数据库具有非常高的读写性,尤其是在大数据量的情况下,表现十分优异。非关系数据库多用于低延时、高并发的场景中,例如股票交易、网络游戏、大数据分析、实时通信等应用。其典型的代表是MongoDB、Redis、Hadoop HBase等。非关系数据库不支持SQL,且不同的数据库语法结构不一致,学习成本较高,另外大多数非关系数据库不支持事务,对数据一致性无法保障,有部分非关系数据也对事务提供了支持,但是与关系数据一样,使用事务时也会降低效率,这样非关系数据库的优势就无法体现出来了。
本章将向读者介绍应用非常广泛的关系数据库MySQL与非关系数据库MongoDB、Redis,并且使用Python作为主要编程语言对这几种数据进行操作。
3.1MySQL简介及安装
3.1.1MySQL简介

MySQL是典型的关系数据库,其应用十分广泛。MySQL最早由瑞典的MySQL AB公司开发,后被甲骨文公司收购,现在是甲骨文公司旗下的产品。MySQL是开放源代码的数据库,它采取了双授权政策,分为社区版和商业版。其中社区版本是完全免费的。
MySQL数据库由于其体积小、速度快、使用成本低,尤其是开放源代码这一特点,很多中小型的网站或者系统会选择MySQL作为其数据库。
作为关系数据库,MySQL将不同的数据保存在不同的表中,而不是将所有数据放在一个大的仓库内,这样就提高了速度和灵活性。
3.1.2MySQL特性
1. 运行速度快
MySQL核心线程是多线程,支持多处理器,从而使处理效率更高。
2. 支持多种存储引擎
MySQL支持的引擎多达十几种,不同的存储引擎有各自的特点,MyISAM、MEMORY与InnoDB是比较常见的存储引擎。InnoDB引擎支持事务的处理。
3. 学习成本低
MySQL使用SQL作为数据库的设计语言。SQL是一种数据库查询和程序设计语言,比较简单,但功能强大。通过简单的语句就可以完成复杂的查询工作。入门比较容易,学习成本低。
4. 存储容量大
在MyISAM存储引擎下,MySQL的存储容量主要受限于操作系统,即操作系统对文件大小的限制,与MySQL本身无关。其他引擎的存储量也十分巨大,对于中小系统来讲,完全不必担心存储的容量限制。
5. 安全性高
灵活的授权形式,既可以按照数据库进行授权,又可以按照用户进行授权,连接服务器时,所有的密码传输均采用加密形式,从而保证了密码的安全。
6. 跨平台
MySQL数据库是跨平台的数据库,可以很好地运行在不同的操作系统上,例如Linux、Windows等操作系统。
7. 支持多语言
支持多种开发语言调用,例如PHP、Python、Java、C、C++、Perl等。
8.  成本低
MySQL社区版可以免费获取并使用,MySQL是一款比较成熟的产品,社区版与商业版在性能方面相差不大,对于大多数中小企业,社区版已经足够使用。
3.1.3MySQL安装
MySQL的官方网站为https://www.mysql.com/。将该网址输入浏览器中并按回车键,就可以访问MySQL的官方网站了,因为该网站存放的服务器在国外,所以从国内访问会较慢,需要耐心等待一下。
成功打开MySQL官网后,单击DOWNLOADS栏目,即可显示MySQL的下载页面,如图31所示。打开DOWNLOADS页面,滑动到页面的最下方,单击MySQL Community (GPL) Downloads链接,进入MySQL社区版的下载页面,如图32所示。

因为需要在Windows操作系统上安装MySQL,所以在MySQL社区版下载页面内选择MySQL Installer for Windows链接,就可以进入Windows安装包的下载界面,如图33所示。在Windows安装包的下载界面有两个下载选项,分别为mysqlinstallerwebcommunity8.0.23.0.msi与mysqlinstallercommunity8.0.23.0.msi,如图34所示。


图31MySQL官方网站





图32MySQL Community(GPL)DownLoads链接


其中mysqlinstallerwebcommunity8.0.23.0.msi表示通过MySQL官方提供的在线安装器进行边下载边安装,而mysqlinstallercommunity8.0.23.0.msi则是完整安装包,一次性下载到本地计算机上后再进行安装,此处选择mysqlinstallercommunity8.0.23.0.msi进行安装,也就是将完整安装包下载到本地后进行安装。

细心的读者可能会发现,MySQL提供的Windows安装包都是基于x86架构32位操作系统的,如果计算机是64位操作系统应该如何选择呢?这里不论是32位操作系统还是64位操作系统,只能选择32位的安装包进行安装。这里的32位安装包只是一个打包器,打包器已经将64位的MySQL打包进去了,在安装MySQL的过程中可以选择64位的MySQL,并且64位是向下兼容32位的,所以选择32位安装包将MySQL打包进去,既可以适配32位的操作系统,也可以兼容64位操作系统。


图33Windows安装包





图34Windows安装包下载页面


在安装包的下载界面可以看到,当前MySQL的最新版本为MySQL 8.0.x(x代表数字,例如MySQL 8.0.23),在下载界面的Archives栏目中的Product Version列表中可以看到MySQL的版本号突然从5.7.32跳到8.0.0,如图35所示,其实这期间并不是MySQL很久没有维护而导致的断代,而是版本命名的规则发生了改变,可以将5.7.32理解为7.0.0,这样比较容易接受。


图35MySQL历史版本号


双击下载好的MySQL安装包(安装包大小为422.4MB),进入MySQL的安装界面,如图36所示,在安装界面有以下选项: 
(1) Developer Default: 安装MySQL开发所需的所有产品。
(2) Server only: 仅安装MySQL服务器端。
(3) Client only: 仅安装MySQL客户端。
(4) Full: 安装MySQL所有产品和功能。
(5) Custom: 用户自定义安装。


图36选择Custom自定义安装


在此选择Custom进行自定义安装,单击Next按钮进入自定义安装界面。MySQL提供的能够安装的产品列表如下。
(1) MySQL Server: MySQL的服务器端,这是必要的数据库程序,所有的数据库都是在MySQL Server下创建的。
(2) MySQL Workbench: MySQL图形化管理工具。
(3) MySQL Shell: MySQL命令行管理工具。
(4) MySQL Router: MySQL的中间件,可以使用MySQL Router来做负载均衡。
(5) MySQL Connectors: 允许其他语言(例如Python、C++等)与MySQL交互的驱动。
(6) documentation: MySQL的说明文档。
(7) samples and examples: MySQL官方提供的案例。
因为本机安装的Python版本是3.9.x的版本,而MySQL官方在本书编写时还没有提供Python 3.8以上版本的Connectors,并且本机也没有安装Visual Studio,所以在选择自定义安装的时候,需要将这两个选项剔除。
在Custom安装界面,提供了两个列表选择框,左侧列表框内是所有可以安装的产品列表,选中左侧列表框中要安装的产品,单击向右的箭头,选中的产品会在右侧列表框中被列出,右侧列表框为即将安装的产品列表。
首先展开MySQL Server前方的加号,直到没有加号为止,选中MySQL Server 8.0.23,然后单击向右的箭头,将MySQL Server 8.0.23移动到右侧列表框中。根据上述步骤,继续选择Applications→MySQL Workbench→MySQL Workbench 8.0→MySQL Workbench 8.0.23,单击向右箭头,将MySQL Workbench 8.0.23移动到右侧列表框中;  选择Applications→MySQL Shell→MySQL Shell 8.0→MySQL Shell 8.0.23,单击向右箭头,将MySQL Shell 8.0.23移动到右侧列表框中;  选择Applications→MySQL Router→MySQL Router 8.0→MySQL Router 8.0.23,单击向右箭头,将MySQL Router 8.0.23移动到右侧列表框中,如图37所示。


图37选择需要安装的产品并移动到右侧列表框


单击Next按钮后便会显示确认页面,继续单击Execute按钮开始安装,在当前页会显示安装进度,需要等待所有的产品出现Complete,如图38所示。


图38耐心等待所有产品安装完毕


安装完毕后,单击Next按钮便会显示确认配置界面,继续单击Next按钮进入配置界面,如图39所示。在配置界面有几个参数需要进行选择与设置。


图39类型及网络设置


Config Type参数提供了3个选项,分别是Development Computer、Server Computer、Dedicated Computer,这3个选项分别对应MySQL服务所占用的资源为低、中、高。因为需要在当前机器上开发及运行其他程序,所以选择Development Computer即可。
Connectivity中有以下几个已选中的参数。
(1) TCP/IP: 使用TCP/IP。
(2) Open Windows Firewall ports for network access: 允许Windows防火墙开放Port端口。
(3) Port: TCP/IP的端口号。
(4) X Protocol Port: MySQL X协议的端口号。
以上参数保留默认选项即可,单击Next按钮,进入认证方式的选择界面,这里有两个认证选项,一个是Use Strong Password Encryption for Authentication,即使用强力认证。另外一个选项是Use Legacy Authentication Method,即使用旧的身份验证方法。为了与后面其他程序相兼容,这里选择旧的身份验证方法,如图310所示,然后单击Next按钮。


图310选择认证方式


进入账号设置界面,这里需要设置root用户的密码,root用户是超级用户,拥有对MySQL操作的所有权限,除了可以设置root密码以外,在当前页面还可以添加新的用户,并且赋予相应的权限。为了操作方便,这里只需设置root用户的密码,该密码需要记住,建议设置常用密码,如图311所示。如果需要对不同的用户区分不同的访问权限,可以通过添加新的用户进行操作。


图311设置用户密码


设置好密码后,单击Next按钮进入Windows Service设置界面,这里使用默认设置即可,如图312所示。


图312Windows Service设置界面


单击Next按钮进入配置确认界面,如图313所示,单击Execute按钮确认执行相关配置。


图313配置确认


单击Execute按钮,确认执行后等待配置生效,然后会出现The configuration for MySQL Server 8.0.23 was successful.Click Finish to continue.及Finish按钮。单击Finish按钮完成安装,如图314所示。


图314单击Finish按钮完成安装


此时完成了MySQL的配置,接下来对MySQL Router进行配置。单击Next按钮进入MySQL Router配置界面,该页面选择默认配置即可,单击Finish按钮回到产品配置页面,继续单击Next按钮进入安装完毕页面,单击Finish按钮即完成了MySQL的安装及配置,如图315所示。


图315配置确认


因为在安装的最后一步勾选了Start MySQL Workbench after setup与Start MySQL Shell after setup,所以在安装完毕后会弹出两个窗口,分别是Workbench与Shell窗口。在Shell窗口内输入\sql并按回车键,将交互语言切换为SQL,前面的\号不能省略,然后输入\connect root@127.0.0.1:3306并按回车键以便连接数据库,其中root是MySQL的用户名,127.0.0.1是本机的IP地址,因为MySQL在当前机器运行,如果MySQL在其他机器运行,则应替换为相应的IP地址。3306是MySQL的端口号,此时会提示输入数据库的密码,将安装时设置的MySQL密码填入即可。
登录后输入select version();就会看到MySQL的版本号,如图316所示。此时MySQL已经顺利地安装完毕。

3.1.4MySQL可视化工具
前文安装的MySQL Shell工具可以通过SQL对MySQL数据库进行全面管理,包括创建及管理数据库、设计及管理数据表、创建及管理存储过程等,也可以对用户及其权限进行管理,但Shell工具界面始终不是太友好,特别对于初学者来讲比较影响使用效率,为此很多第三方产品提供了针对MySQL的可视化工具,包括MySQL官方也提供了自己的可视化工具。下面将要介绍两个比较常用的MySQL可视化工具,一个是由MySQL官方提供的可视化工具MySQL Workbench,另一个是由第三方提供的可视化工具Navicat for MySQL。


图316MySQL Shell操作


1. MySQL Workbench
MySQL Workbench是MySQL官方提供的一款免费的可视化工具,即能在命令行下完成的内容,在可视化工具内都可以完成,反之亦成立。在上文安装MySQL的同时,选择并安装了MySQL Workbench,可以通过“开始”菜单的“最近添加”列表中的MySQL Workbench 8.0 CE打开MySQL Workbench,如图317所示。


图317打开MySQL Workbench 8.0 CE


第一次打开MySQL Workbench后会看到欢迎界面,如图318所示。Workbench布局采用上、左、右的模式,上部分是菜单项,所有的操作都可以通过菜单完成; 左侧有3个选项,分别是数据库管理、模型管理及迁移向导; 右侧为相对应的操作界面。
在欢迎界面的左下角Workbench已经识别出当前机器所安装的MySQL,可以单击Local instance MySQL80卡片来连接本机的MySQL,也可以通过新建的方式来连接本地的MySQL。这里选择创建新的连接方式来连接本地的MySQL,选择菜单Database→Manage Connections选项会弹出新建连接的对话框,如图319所示。


图318Workbench欢迎界面




图319新建MySQL连接


在设置参数前,单击左下角的New按钮来创建新的连接。新连接有以下参数需要进行设置。
(1) Connection Name: 设置连接名称,填写容易辨识的名称,可以使用中文。例如本机MySQL数据库。
(2) Connection Method: 选择连接数据库的方式,默认选择TCP/IP。
(3) Hostname: 要连接的数据库服务器的IP地址,本机将此IP设置为127.0.0.1。
(4) Port: 要连接的数据库服务器的端口,默认端口为3306。
(5) Username: 连接MySQL的用户名,root为默认的超级管理员。
(6) Password: 连接MySQL的密码,通过Store in Vault保存。
将以上的参数设置完成后,单击Test Connection按钮以便测试是否正常连接,如果参数都正确,则会提示Successfully made the MySQL connection,如图320所示。


图320连接MySQL成功


新建连接成功后,会在Workbench欢迎界面多了一个新建的MySQL连接卡片。单击该卡片就可以进入MySQL的管理界面了,如图321所示。


图321MySQL管理界面


MySQL管理界面里面的内容比较多,这里应重点关注对数据库的管理及操作,选择Navigator面板下方的Schemas选项卡,切换至数据库管理列表。在SCHEMAS面板可以看到默认有一个系统数据库sys,在SCHEMAS面板的空白处右击,在弹出的菜单中选择Create Schema选项,在右侧会切换至创建数据库界面,如图322所示。


图322创建新的数据库


创建数据库界面中的参数设置如下。
(1) Name: 数据库名,可设置任何名称,但不建议使用中文,例如mydata。
(2) Charset/Collation: 字符编码,建议选择为utf8和utf8_unicode_ci,可以支持中文。
单击Apply按钮,弹出一个对话框,提示检查创建数据库的脚本,如图323所示。在MySQL中,一切都可以使用SQL进行创建、控制和管理。此时依然单击Apply按钮,然后在弹出的对话框中单击Finish按钮,完成mydata数据库的创建。


图323脚本检查对话框


创建完数据库后,在SCHEMAS面板中会多出一个刚才创建的mydata数据库。单击mydata数据库前面的三角按钮便可展开数据库,在数据库下有Tables、Views、Stored Procedures、Functions,分别为数据表、视图、存储过程、存储函数。这里创建新的数据表,右击Tables在弹出的菜单中选择Create Table选项,则可进入数据表创建界面,如图324所示。


图324创建数据表


创建数据表界面中的参数设置如下。
(1) Table Name: 数据表的名称可以随意填写,例如mytable,但不建议使用中文。
(2) Charset/Collation: 字符编码,这里分别选择utf8和utf8_unicode_ci。
(3) Engine: MySQL使用的存储引擎,这里选择InnoDB,InnoDB用于支持事务。
以上参数设置完成后,需要进一步设计表结构,单击图324右侧向上的两个箭头,切换到表设计界面,双击Column Name下方反选处,即可添加新的字段,如图325所示。


图325设计字段


在表中添加3个Column Name,分别为id、username、password,它们的Datatype分别为INT、VARCHAR(45)、VARCHAR(45),其中45表示该字段可以存放最多45个字符。对于VARCHAR类型的字段需要将下方的Charset/Collation参数设置为utf8、utf8_unicode_ci。对于id字段,需勾选Primary Key、Not Null、Auto Increment复选框,它们分别代表主键、不为空、自增,如图326所示。单击Apply按钮,同样会弹出脚本检查对话框,继续单击Apply按钮及Finish按钮完成表设计,右侧Tables会出现一个三角形按钮,单击三角形按钮即可看到刚才创建的mytable表,右击mytable并在弹出的菜单中选择Select Rows选项,可以看到表详情,如图327所示。至此,使用MySQL Workbench完成了MySQL的连接、数据库的创建及数据表的创建。


图326字段设计完毕





图327查看表详情


2. Navicat for MySQL
Navicat for MySQL是一款比较流行的MySQL可视化工具,它是一款商业软件,但是因其简洁易用、功能强大的特性,深得从业人员的喜爱。Navicat是一个系列产品,主要为各种数据库的可视化工具,这里使用的是Navicat for MySQL。
打开Navicat官方网站,网址为http://www.navicat.com.cn/,选择“产品”栏目,选择Navicat for MySQL进行下载并安装,可以免费试用14天。其安装比较简单,在此不再赘述。
打开Navicat for MySQL界面,如图328所示,中文界面,界面比较简洁。如果你的界面不是中文,可通过工具→选项→常规→语言选项,选择简体中文,重启Navicat后生效。界面默认的布局与Workbench的布局一样,也是上、左、右的形式。
界面上部是菜单及常用功能,所有的操作都可以通过此处完成。界面左侧是连接的对象,右侧是对应对象的操作。初次打开左侧列表可能为空白,或者只有一个本地数据库。


图328Navicat for MySQL可视化界面


与Workbench一样,可使用Navicat for MySQL连接服务器、创建数据库、创建数据表。在创建数据库前,需要先连接目标MySQL服务器,单击常用工具中的“连接”按钮,选择MySQL选项将会弹出连接对话框,如图329所示。
该对话框中的参数设置如下。
(1) 连接名: 填写容易辨识的名称,可以使用中文,例如本机MySQL
(2) 主机: 填写IP地址或者域名,因连接的是本机,所以IP地址为127.0.0.1,亦可以使用localhost代替。
(3) 端口: MySQL安装时设置的默认端口为3306。
(4) 用户名: 登录MySQL的用户名,这里使用超级用户root。
(5) 密码: 登录MySQL的密码。
以上参数都设置完成以后,单击“测试连接”按钮,如果参数设置正确,则会提示连接成功,然后单击“确定”按钮,在左侧连接列表面板中会出现刚才添加的“本机MySQL”的连接名。


图329使用Navicat for MySQL连接MySQL服务器


双击刚才创建的本机MySQL,将会连接MySQL服务器,并且展开该MySQL下的所有数据库列表,这时可以看到之前使用Workbench所创建的数据库mydata。双击mydata即可看到数据库下的表mytable,如图330所示。


图330mytable表


右击连接名“本机MySQL”,在弹出的菜单中选择“新建数据库”选项来创建一个新的数据库。创建对话框中的参数设置如下。
(1) 数据库名: 填写具有辨识度的名称,不建议使用中文,例如newdatabase。
(2) 字符集: 选择utf8。
(3) 排序规则: 选择uft8_unicode_ci。
单击“确定”按钮则可完成一个名为newdatabase数据库的创建,如图331所示。


图331使用Navicat for MySQL创建新的数据库


双击左侧数据库列表中已创建的newdatabase数据库即打开了该数据库。在其展开的表上右击,在弹出菜单中选择“新建表”菜单,这样就可创建一张新表了,并且进入了表的设计界面,如图332所示。同样在此表内添加3个字段,分别为id、username、password,字段类型分别为int、varchar、varchar,varchar的长度设置为45,其中id将勾选“不是null”,接着点选“键”及选择“自动递增”。username与password字符集设置为utf8、排序规则设置为utf8_unicode_ci。按快捷键Ctrl+S保存该表,存储名称为newtable。


图332使用Navicat for MySQL创建新表


至此使用Navicat for MySQL完成了MySQL服务器的连接、创建了新的数据库newdatabase、在newdatabase下创建了新的表newtable。如果要执行SQL语句对指定数据库进行操作,则需要先选中该数据库,然后单击常用菜单中的“查询”按钮,单击“新建查询”按钮即可写入SQL语句并执行。例如想要查询newdatabase数据库中的newtable表中的所有内容,应先单击newdatabase,然后单击“查询”按钮新建查询,如图333所示。输入代码如下: 


select * from newtable

#数据结果为newtable下的所有内容



图333使用Navicat for MySQL执行SQL语句


3.1.5MySQL基础
1. MySQL数据库与表


7min

在一个MySQL服务器中可以同时保存多个数据库,每个数据库可以分别设置不同的访问权限。在使用数据库时通过数据库命名来区分,且命名方式不区分大小写,所以数据库名不能相同。
在一个数据库内可以同时存在多张表,表之间的命名也不能相同。每张表之间应当有相应的字段进行关联,在关系型数据库中数据表一般不应独立存在。
2. 字段的数据类型
MySQL支持多种数据类型,其类型如表31所示。


表31MySQL数据类型



类型说明

bigint极大整数值,取值范围为-2^63(-9223372036854775808)~2^63-1
(9223372036854775807)

binary固定长度二进制字符串

bit位字段类型,范围为1~64 

blob二进制字符串,最大为65KB(单位为字节)

char定长字符串,最大长度为255字节
续表


类型说明

date日期类型 YYYYMMDD

datetime日期与时间类型 YYYYMMDD HH:MM:SS

decimal精确定点类型,DECIMAL的数字总长度M,最大为65,但是实际能表示的数值范围受精度和标度的限制

double双精度浮点型

enum枚举类型

float单精度浮点型

geometry任意一种空间类型

geometrycollection任意一种空间类型集合

int整数型,字段默认值为0,取值范围为-2^31(-2147483648)~2^31-1(2147483647)

integer整数型,字段默认值为null

jsonjson类型

longblob二进制字符串,最大为4GB(单位为字节)

longtextBLOB或TEXT类型

mediumblob二进制字符串,最大为16MB(单位为字节)

mediumint整数型

mediumtextBLOB或TEXT类型

linestring线类型,由一系列点连接而成

multilinestring线集合,包含多条线

multipoint点集合,包含多个点

multipolygon多边形集合,包含多个多边形

numeric精确定点类型

point空间类型

polygon多边形类型

real不精确的双精度浮点型

set集合类型

smallint整数型,取值范围为-2^15(-32768)~2^15-1(32767)

text字符串类型,最大长度为65535字节

time时间类型

timestamp时间戳类型

tinyblob二进制字符串,最大长度为255字节

tinyint整数型,取值范围为0~255
 
tinytext字符串类型,最大长度为255字节

varbinary可变长度的二进制数据,取值范围为1~8000

varchar字符串类型,最大长度为65535字节

year年份类型

3. 字段的属性
字段拥有以下属性。
(1) Primary Key(主键): 通过唯一索引对给定的一列或多列强制实体完整性的约束。对于每个表只能创建一个 PRIMARY KEY 约束。
(2) Not Null(不为空): 指字段的值不能为空。
(3) Unique(唯一约束): 通过唯一索引为给定的一列或多列提供实体完整性的约束。一个表可以有多个 UNIQUE 约束。
(4) Binary(区分大小写): 字段区分大小写。
(5) Unsigned(无符号): 表示不允许负值。
(6) Zero Fill(填充): 插入数据时,当该字段的值的长度小于定义的长度时,会在该值的前面补上相应的0。
(7) Auto Increment(自动递增): 当给定某个字段该属性后,该列的数据在没有提供确定数据的时候,系统会根据之前已经存在的数据进行自动增加,以便填充数据。
(8) Generated(虚拟自增列): 该列由其他列计算而得。
4. MySQL事务
MySQL事务主要用于处理操作量大且复杂度高的数据。例如订单系统,用户购买了一件商品,下了一个订单并支付,此时要生成一个订单记录,在用户未支付时订单状态为未支付,商品的库存数量也保持不变,当用户支付后,此时要将订单状态修改为已支付,并且同时将商品的库存数量减1,这些数据库操作就构成了一个事务。
在MySQL中,只有InnoDB存储引擎才支持事务,事务的特点是要么全部执行成功,要么全部执行失败,不会存在一半成功一半失败的情况。例如上面的例子,使用事务操作时,不会出现订单的支付状态被修改了,而商品的库存数量却没有减少的情况。
在MySQL中,使用BEGIN开始一个事务,使用ROLLBACK对事务进行回滚,使用COMMIT对事务进行确认。示例代码如下: 


BEGIN -- 开始事务

select * from order; 

insert into user values("jack","123456");

insert into newtable values("abcdef","python开发");

COMMIT -- 提交事务



22min

3.2SQL
SQL(Structured Query Language)即结构化查询语言,是一种数据库查询和程序设计语言,用于存取数据库及查询、更新和管理关系数据库系统。
SQL是高级非过程化编程语言,与普通编程语言不同,它不需要对数据进行定义、存储等。它是基于高层数据结构之上工作的语言。结构化查询语言可以嵌套,这使它具有极大的灵活性和强大的功能。
SQL常见的操作是对数据表进行创建,以及对数据表中的记录进行读取、增加、编辑、删除等操作,利用Navicat for MySQL可以直接对表进行操作,大多数时候使用SQL语句对数据表进行操作。
SQL本身不区分大小写,但是不同的操作系统有可能会区分大小写,例如在Windows操作系统中,SQL不区分大小写,而在Linux系统中,有可能会因为大小写而产生一些意料之外的问题,所以在写SQL语句的时候,大小写应当保持统一。
1. 使用SQL创建表
使用SQL语言创建表的语法如下: 


CREATE TABLE 表名 (

字段1字段1类型字段1属性,

字段2字段2类型字段2属性

);

打开Navicat for MySQL,双击指定的数据库,单击快捷菜单中的“查询”→“新建查询”按钮便可创建一个新的查询。在新建查询界面可以输入SQL语句并执行,例如创建一个newtable数据表并设置3个字段,分别为id、user、pass,对应的数据类型分别为int、varchar、varchar,创建表的SQL代码如下: 


CREATE TABLE 'newtable'  (

-- 创建字段id、设置为整型、设置不为空、设置自动增长

'id' int NOT NULL AUTO_INCREMENT,

-- 创建字段user、设置为字符串型,字符宽度为45、设置为utf8格式、设置允许为空、--设置默认为空

'user' varchar(45) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,

-- 创建字段pass、设置为字符串型,字符宽度为45、设置为utf8格式、设置允许为空、--设置默认为空

'pass' varchar(45) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,

-- 将id设置为主键

PRIMARY KEY ('id') USING BTREE

)

单击“运行”按钮会弹出信息栏,并在信息栏内输出OK及SQL代码运行的时长,在左侧刷新后会出现刚才创建的newtable表,如图334所示。如果没有出现OK按钮,则说明SQL代码存在错误,在错误代码中会提示大概在哪个位置有错误,根据错误提示修改代码直到输出OK为止。
在上面的代码中,使用双横线可以为SQL代码添加注释。需要注意的是注释与双横线之间有空格,如果不写空格SQL则会报错。
双击左侧新建的表即可进入刚刚创建的表中,该表没有使用可视化界面来创建,而是完全使用SQL语言进行创建的。


图334Navicat for MySQL下使用SQL创建新表


2. 使用SQL读取数据
使用SQL语言读取表的语法如下: 


SELECT 字段名 FROM 表名 

同样使用Navicat for MySQL来执行读取语句,按照前文创建表的方式进入查询界面,查询刚才创建的newtable表中的所有字段,则SQL代码如下: 


-- 查询id,user,pass字段

SELECT id,user,pass FROM newtable

因为创建的newtable表中没有任何数据,所以将输出一张空表,如图335所示。


图335Navicat for MySQL下使用SQL查询表


当表中字段特别多时,如果想要将所有的字段一次性查询出来,则可以使用通配符*来代替所有字段进行输出,SQL代码如下: 


-- 查询id,user,pass字段

SELECT * FROM newtable

一般情况下,使用SQL查询表时都会输出结果,如果查询语句内有错误,则会输出错误信息,并指明哪里发生了错误,需要进行修改,直到输出结果为止,在其信息面板也会输出OK。
3. 使用SQL增加记录
使用SQL语言增加记录的语法如下: 


INSERT INTO 表名称 (列1, 列2,...) VALUES (值1, 值2,....)

如果按照字段顺序来添加内容并且每个字段都有内容,则(列1,列2,...)可以省略。例如在newtable中增加一条记录,同样先进入Navicat for MySQL查询界面,SQL代码如下: 


-- 为newtable新增一条记录,id为自增字段,所以不用设置id

INSERT INTO newtable (user,pass) VALUES ("jack","123456")

-- 省略列

INSERT INTO newtable VALUES ("jack","123456")



#输出结果为

> Affected rows: 1

> 时间: 0.014s

使用SQL语言新增记录时,如果新增记录被正常地插入了表中,则在结果中会显示影响了多少行,但插入数据不会显示结果。如果需要查看插入的数据,则可以再次使用SELECT查询语句来查询表的内容。例如要查看刚才插入的记录,SQL代码如下: 


SELECT * FROM newtable

输出结果如图336所示。


图336SQL查询结果


4. 使用SQL编辑记录
使用SQL语言编辑记录的语法如下: 


UPDATE 表名称 SET 列名称=新值 WHERE 列名称=某值

更新表中的记录应使用UPDATE关键字,例如要将上文查询到的jack的密码修改为abcd,SQL代码如下: 


UPDATE newtable SET pass="abcd" WHERE user="jack"

输出结果为

> Affected rows: 1

> 时间: 0.013s

修改指定的行的记录时需要在后面附上条件语句,例如上面的 WHERE user="jack"就是条件语句,WHERE是条件语句的关键字,即指定user字段中记录为jack这一行的记录,并将其对应的pass字段修改为abcd。
与INSERT一样UPDATE语句执行后并不展示任何结果,只是输出代码运行的结果。如果代码执行顺利并执行完毕,则会返回代码影响的行数,以及代码执行的时间。如需要查看结果,同样可使用SELECT将其结果查询出来,如图337所示。此时jack行的pass已经由原来的123456修改为abcd了。


图337修改字段值后的结果


5. 使用SQL删除记录
使用SQL语言删除记录的语法如下: 


DELETE FROM 表名称 WHERE 列名称=值

与UPDATE类似,在删除记录时需要使用条件语句指定要删除哪一行数据。例如要将上文的jack记录删除,SQL代码如下: 


DELETE FROM newtable WHERE user="jack"



#输出结果为

> Affected rows: 1

> 时间: 0.016s




注意删除操作如果不指定条件语句,则会将该表中所有的数据删除。




删除操作也只会返回代码执行的状态,而不会返回表中的内容。使用SELECT来查询newtable,会发现jack所在的行已经被删除了,如图338所示。


图338删除记录后的结果


6. SQL条件语句
前文进行删除、编辑的时候,需要指明条件以便对哪一行进行操作,使用WHERE关键字进行指定。特别是删除操作,如果不指定删除某一行,则会将表中的所有数据删除。
在SQL语言中使用WHERE关键字设置条件。对表的查询(SELECT)、删除(DELETE)、更新(UPDATE)等需要对具体记录进行的操作,都需要使用WHERE语句设置操作条件。示例代码如下:


-- 查询user字段为jack的记录

SELECT * FROM newtable WHERE user="jack"



-- 修改user字段为jack的记录,将该记录中的pass设置为123

UPDATE newtable SET pass="123" WHERE user="jack"



-- 删除user字段为jack的记录

DELETE FROM newtable WHERE user="jack"

WHERE后面除了可以使用等号操作符之外,也可以使用很多其他的操作符,具体操作符列表如表32所示。


表32操作符说明



操作符说明

=等于

<>不等于

!=不等于

<小于

>=大于或等于

<=小于或等于

BETWEEN在某个范围内

LIKE匹配某种模式

在WHERE中还可以使用AND、OR进行多条件判断,示例代码如下: 


-- 查询user字段为jack并且pass字段为123的记录

SELECT * FROM newtable WHERE user="jack" AND pass="123"



-- 查询user字段为jack或者为marry的记录

SELECT * FROM newtable WHERE user="jack" OR user="marry"

7. SQL去重
使用DISTINCT关键词查询指定字段不重复的记录,语法如下: 


SELECT DISTINCT 字段 FROM 表



图339表中user字段含有相同的值

当统计newtable表中所有的用户时,会发现user字段中有两个相同的jack,如图339所示。
使用SELECT进行查询时,会将两条相同的数据都查出来,使用DISTINCT关键字就可以显示去重的记录,代码如下: 


SELECT DISTINCT user FROM newtable 



#输出结果为

user

jack

marry

8.  查询排序
SQL中使用ORDER BY语句对结果集进行排序,示例代码如下: 


SELECT * FROM newtable ORDER BY id

此时将会使用id字段进行升序排序,如果希望使用降序排序,则可加上DESC关键字,代码如下: 


SELECT * FROM newtable ORDER BY id DESC

在使用排序时,指定的排序字段应可以进行排序,否则可能排出的结果与想要的结果不一致。例如排序的字段类型指定为字符串,且包含的记录中有数字样式的字符串、字母样式的字符串及符号样式的字符串,此种情况的排序结果是不可控的。
9.  返回指定行数
在MySQL中使用LIMIT关键字获取指定条数的数据,其语法如下: 


SELECT * FROM 表 LIMIT 起始行数,条数

当数据表中的记录特别多的时候,例如当在newtable表中有一百万行记录时,此时想要对最早入库的5条记录进行操作,就需要使用LIMIT来限制读取记录的条数。否则将一百万行记录都读取出来再进行操作,这个时间将会很长,稍差点的计算机可能还会出现卡顿现象。
使用LIMIT关键字的示例代码如下: 


SELECT * FROM newtable LIMIT 0,10

注意该段代码的含义,此处并不是读取从0条到第10条的记录,而是从第0条开始,读取10条记录,这里面的含义是不一样的。再举个例子,代码如下: 


SELECT * FROM newtable LIMIT 5,10

上面这段代码不是读取从第5行到第10行的记录,而是从第5行起但不包含第5行,读取10行记录,也就是读取的是第6行到第15行的记录。这里比较容易混淆,读者需要注意。
3.3使用Python操作MySQL
3.3.1MySQL操作模块

在MySQL官方网站中,提供了便于其他语言连接并对MySQL进行操作的驱动程序Connectors,也包括Python语言,但是当前MySQL官方提供的连接驱动在本书写作期间最高只支持Python 3.8,而本书使用的Python是3.9.x版本,所以无法使用MySQL官方提供的驱动程序。
除了MySQL官方提供的操作模块之外,还有很多非常流行的第三方模块,例如PyMySQL模块与mysqlclient模块,这两个模块都支持Python 3,两个模块各有特点。
PyMySQL模块使用纯Python开发,安装与使用都比较简单,相对于mysqlclient模块来讲处理速度慢一些,适用于中小型的项目。
mysqlclient模块是基于C语言的,所以其速度比较快,但其缺点是安装起来比PyMySQL复杂,对新手来讲不太友好。
两个模块除了安装有所区别以外,对于使用Python操作数据库方面大同小异,因此本书将使用PyMySQL模块来操作数据库。
3.3.2使用Python操作MySQL
因PyMySQL是第三方模块,所以在使用前需要对其进行安装。首先打开PyCharm编辑器,然后单击View→Tool Windows→Terminal打开终端窗口,在命令行中输入pip install PyMySQL并按回车键来安装PyMySQL模块,等待提示Successfully installed PyMySQL后即可使用。关于pip的使用方式,在前文已经详细讲过,这里不再赘述。
1. 连接MySQL数据库
使用Python连接数据库前,先要确保数据库已经被正确创建,可以使用Navicat for MySQL创建新的数据库,这里使用前文已经创建过的数据库newdatabase。连接数据库的代码如下: 


#第3章//mysqls.py

import pymysql#导入pymysql模块

db=pymysql.connect(user="root",password="123456",host="localhost",database="newdatabase")#连接数据库

cur=db.cursor()#创建一个游标对象

cur.execute("SELECT VERSION()")#执行SQL语句

data=cur.fetchone()#获取单条数据

print("Database version:%s"%data)

db.close()



#输出结果为Database version:8.0.23

PyMySQL模块中的connect()方法用于连接MySQL数据库,其包含的参数如下。
(1) host: 要连接的主机地址。
(2) user: 用于登录的数据库用户。
(3) password: 数据库密码。
(4) database: 要连接的数据库。
(5) port: 数据库的端口,MySQL默认端口为 3306。
(6) unix_socket: 选择是否要用unix_socket而不是TCP/IP。
(7) charset: 字符编码。
(8) sql_mode: 数据库模型。
(9) read_default_file: 从默认配置文件(my.ini或my.cnf)中读取参数。
(10) conv: 转换字典。
(11) use_unicode: 是否使用 unicode 编码。
(12) cursorclass: 选择 Cursor 类型。
(13) init_command: 连接建立时运行的初始语句。
(14) connect_timeout: 连接超时时间。
(15) ssl: 使用ssl连接。
(16) read_default_group: 要从配置文件中读取的组。
(17) autocommit: 是否自动提交事务。
(18) db: 同 database,为了兼容 MySQLdb。
(19) passwd: 同 password,为了兼容 MySQLdb。
(20) local_infile: 是否允许载入本地文件。
(21) max_allowed_packet: 限制LOCAL DATA INFILE的大小。
(22) bind_address: 当客户有多个网络接口时,指定一个连接到主机。
connect()方法的参数比较多,所以在定义参数时最好使用关键字参数。连接数据库后,创建一个游标对象。游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。游标可以被看作一个查询结果集(可以是零条、一条或由相关的选择语句检索出的多条记录)和结果集中指向特定记录的游标位置组成的一个临时文件,提供了在查询结果集中向前或向后浏览数据、处理结果集中数据的能力。有了游标,用户就可以访问结果集中任意一行数据,在将游标放置到某行后,可以在该行或从该位置的行块上执行操作。
使用execute()方法执行了SQL语句SELECT VERSION(),该方法包含两个参数,分别为SQL语句及args参数,execute()方法中sql的占位符是用小括号()括起来的占位符,示例代码如下: 


...

cur.execute("insert into newtable(username) values (%s)",val)

...

args一般是list或tuple格式,如果只有一个参数,则可以直接传入。fetchone()方法用于返回数据集中的一条元素,与其同类型的还有fetchall(),用于返回全部记录。fetchmany(n)返回n条记录。
2. 创建表
创建表前需要确保已经连接至数据库,使用execute()方法执行创建表的SQL语句,下面创建一个表并命名为news,用于存储新闻文章,字段分别为id、title、bodys,数据类型分别为int、varchar(45)、varchar(100),其中id为主键并且自动增长,title与bodys设置为utf8编码,示例代码如下: 


#第3章//mysqls.py

import pymysql

db=pymysql.connect(user="root",password="123456",host="localhost",database="newdatabase")#连接数据库

cur=db.cursor()

cur.execute("DROP TABLE IF EXISTS news")#如果表存在则删除

sql="""

CREATE TABLE news (

id int NOT NULL AUTO_INCREMENT,

title varchar(45) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,

bodys varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,

PRIMARY KEY (id) USING BTREE

) ENGINE=InnoDB CHARACTER SET=utf8 COLLATE=utf8_unicode_ci




"""

cur.execute(sql)#执行SQL语句

db.close()

3. 插入数据
往上文创建的表中插入数据,示例代码如下: 


#第3章//mysqls.py

import pymysql

db=pymysql.connect(user="root",password="123456",host="localhost",database="newdatabase")#连接数据库

cur=db.cursor()

args=("标题","内容")

sql="INSERT INTO news (title,bodys) VALUES (%s,%s)"

cur.execute(sql,args)#执行SQL语句

db.commit()#手动提交到数据库执行

db.close()

如果连接数据库时没有指定自动提交事务,则需要在执行代码后手动提交,即使用commit()方法。
4. 查询数据
使用fetchone()、fetchall()、fetchmany(n)处理查询出的结果集,fetchone()方法用于返回数据集中的一条元素,fetchall()方法用于返回全部记录,fetchmany(n)方法用于返回n条记录。使用fetchall()处理数据集的示例代码如下: 


#第3章//mysqls.py

import pymysql

db=pymysql.connect(user="root",password="123456",host="localhost",database="newdatabase")#连接数据库

cur=db.cursor()

sql="SELECT * FROM news"

cur.execute(sql)#执行SQL语句

db.commit()#手动提交到数据库执行

result=cur.fetchall()#处理数据集

for i in result:

print(i)

db.close()



#输出结果为

(4, '5435', '534543')

(6, '标题', '内容')

(7, '标题1', '内容1')

(8, '标题', '内容')

5. 更新数据
更新id为4的数据,并将title修改为aaa,将bodys修改为bbb,示例代码如下: 


#第3章//mysqls.py

import pymysql

db=pymysql.connect(user="root",password="123456",host="localhost",database="newdatabase")#连接数据库

cur=db.cursor()

args=("aaa","bbb",4)

sql="UPDATE news set title=%s,bodys=%s where id=%s"

cur.execute(sql,args)#执行SQL语句

db.commit()#手动提交到数据库执行

print("更新成功")

db.close()



#输出结果为更新成功

6. 删除数据
删除id为4的数据,示例代码如下: 


#第3章//mysqls.py

import pymysql

db=pymysql.connect(user="root",password="123456",host="localhost",database="newdatabase")#连接数据库

cur=db.cursor()

args=4

sql="DELETE FROM news where id=%s"

cur.execute(sql,args)#执行SQL语句

db.commit()#手动提交到数据库并执行

print("删除成功")

db.close()



#输出结果为删除成功

7. 执行事务
PyMySQL中可使用commit()及rollback()两种方法来完成一个事务的处理,示例代码如下: 


#第3章//mysqls.py

import pymysql

db=pymysql.connect(user="root",password="123456",host="localhost",database="newdatabase")#连接数据库

cur=db.cursor()

sql="DELETE FROM news where id=4"

sql2="DELETE FROM news where id=6"

try:

cur.execute(sql)

cur.execute(sql2)

db.commit()

except:

db.rollback()

db.close()

在上面的代码中多个SQL语句同时执行,要成功则一起成功,如果有一个执行不成功,则全部不成功,执行不成功需使用rollback()方法进行回滚。回滚是指将数据恢复到上一次状态的行为。
3.4MongoDB简介及安装
3.4.1MongoDB简介

MongoDB属于非关系型数据库,它由C++语言编写,旨在为Web应用提供可扩展的高性能数据库存储及解决方案。MongoDB是开源的产品,与MySQL类似,除企业版本及一些增值服务以外,MongoDB本身对用于商用是不收取费用的。
MongoDB(来自于英文单词Humongous,中文含义为“庞大”)是可以应用于各种规模的企业、各个行业及各类应用程序的开源数据库。作为一个适用于敏捷开发的数据库,MongoDB的数据模式可以随着应用程序的发展而灵活地更新。与此同时,它也为开发人员提供了传统数据库的功能: 二级索引、完整的查询系统及严格一致性等。 MongoDB能够使企业更加具有敏捷性和可扩展性,各种规模的企业都可以通过使用MongoDB来创建新的应用,提高与客户之间的工作效率,加快产品上市时间,以及降低企业成本。
MongoDB是专为可扩展性、高性能和高可用性而设计的数据库。它可以从单服务器部署并扩展到大型、复杂的多数据中心架构。利用内存计算的优势,MongoDB能够提供高性能的数据读写操作。 MongoDB的本地复制和自动故障转移功能使应用程序具有企业级的可靠性和操作灵活性。
3.4.2MongoDB特性
1. 文档型数据库
文档型数据库存储格式是版本化的文档、半结构化的文档及特定格式存储,例如JSON。文档型数据库允许嵌套键值,但比键值数据库的查询效率更高。文档型数据库操作起来也比较简单和容易。
2. 高可用
MongoDB提供了数据副本,当发生硬件故障或者服务中断时,可以从副本恢复数据,并能自动进行故障转移。运维简单,故障自动切换。
3. 高性能
mmapv1、wiredtiger、mongorocks(rocksdb)、inmemory 等多种存储引擎支持满足各种场景需求。
4. 易部署
MongoDB支持多种平台,如Windows、Mac OS、Linux等。官方提供非常详细的部署资料,多数云平台直接支持MongoDB。可以非常方便地创建单例MongoDB及MongoDB集群。
5. 模式自由
模式自由(SchemaFree),意味着对于存储在MongoDB数据库中的文件,我们不需要知道它的任何结构定义。如果需要,则完全可以把不同结构的文件存储在同一个数据库中。
6. 面向集合
所谓“面向集合”(CollectionOriented),意思是数据被分组存储在数据集中,被称为一个集合(Collection)。每个集合在数据库中都有一个唯一的标识名,并且可以包含无限数目的文档。集合的概念类似于关系数据库(RDBMS)里的表(table),不同的是它不需要定义任何模式,能够快速识别数据库内大数据集中的热数据,提供一致的性能改进。
7. 多语言支持
支持Perl、PHP、Java、C#、JavaScript、Ruby、C 和C++语言的驱动程序,MongoDB 提供了当前所有主流开发语言的数据库驱动包,开发人员使用任何一种主流开发语言都可以轻松编程,实现访问MongoDB 数据库。
3.4.3MongoDB安装
1. Windows平台下MongoDB的安装
MongoDB的官方网站为https://www.mongodb.com,与MySQL相同的是,MongoDB同样也分为社区版与企业版,社区版是免费开源的,企业版包含了一些增值服务。日常开发选择社区版就足够用了。
打开MongoDB官网→Software 单击Community Server菜单即可显示社区版MongoDB的下载页面,如图340所示。在页面的MongoDB Community Server这一栏右侧可以选择MongoDB的版本进行下载,在本书的写作期间,MongoDB的最高版本为4.4.4,平台选择Windows,选择msi安装包,单击Download按钮即可开始MongoDB的下载。


图340下载MongoDB


双击下载好的MongoDB安装包即可开始对MongoDB进行安装,前两页单击Next按钮进行下一步。在Choose Setup Type页面MongoDB提供了安装模式的选择,该页面有两个选项,一个是完全安装,另一个是自定义安装,如图341所示。


图341选择安装模式


这里选择Custom,即自定义安装,单击Custom按钮即可显示自定义安装界面,如图342所示。


图342自定义安装


在自定义安装界面可见准备安装到计算机上的程序包,共含4部分,Server为MongoDB的服务器端主程序,Client为MongoDB的客户端工具,Router向外提供应用访问的接口,Miscellaneous Tools为MongoDB的一些其他工具。这里默认为都选中,按默认值安装即可。
在Location处选择要安装的路径,此处选择任意目录即可,切记目录中不要有中文字符及其他特殊字符,例如圆角空格等,因为这些字符有可能会产生一些意料之外的错误。选择好目录以后单击Next按钮,来到服务配置界面,如图343所示。此时默认勾选了Install MongoD as Service,即将MongoDB作为服务安装到Windows操作系统上,这样做的好处是随着系统的启动,MongoDB也跟着启动,所以此处要勾选。
在其下方有两个选项,分别为Run service as Network Service user(使用网络用户运行服务),以及Run service as a local or domain user(以本地域或用户身份运行服务),此处使用默认选择,即Run service as Network Service user。
(1) Service Name为设置MongoDB服务的服务名称,此处默认为MongoDB。
(2) Data Directory为设置数据库文件的存储目录。
(3) Log Directory为设置日志文件的目录。
设置完毕后单击Next按钮进入MongoDB Compass安装界面,如图344所示。MongoDB Compass为MongoDB的图形化工具,此处勾选Install MongoDB Compass,单击Next按钮进入下一步。继续单击Install按钮开始MongoDB的安装,安装时间比较长,需要耐心等待进度条读取完毕,然后单击Finish按钮即完成了MongoDB的安装。


图343配置MongoDB





图344安装MongoDB Compass


2. Linux平台下MongoDB的安装
打开MongoDB的官方网站,网址为https://www.mongodb.com,单击Software→Community Server链接进入MongoDB Community Server下载页,因为笔者的Linux操作系统是CentOS 7.9,所以在右侧Available Downloads面板中的Platform栏选择RedHat/CentOS 7.0,注意不要选择RedHat/CentOS 7.2 s390x。在Package栏选择server,如图345所示。


图345MongoDB下载页面


如果不知道自己安装的CentOS的具体版本是多少,可以使用如下命令在命令行执行,命令如下: 


cat /etc/redhat-release



#输出结果为CentOS Linux release 7.9.2009 (Core)

选择好平台和包后,单击Download旁边的Copy Link链接,复制rpm包链接地址。地址为https://repo.mongodb.org/yum/redhat/7/mongodborg/4.4/x86_64/RPMS/mongodborgserver4.4.41.el7.x86_64.rpm。获取rpm包链接后,在CentOS命令行中执行如下命令


wget -i -c https://repo.mongodb.org/yum/redhat/7/mongodb-org/4.4/x86_64/RPMS/mongodb-org-server-4.4.4-1.el7.x86_64.rpm

该命令会下载一个mongodborgserver4.4.41.el7.x86_64.rpm的包文件,当文件下载完毕后,安装该包,命令如下: 


yum -y install mongodb-org-server-4.4.4-1.el7.x86_64.rpm

等待文件安装完毕,出现Complete后表示MongoDB Server安装完成了。启动MongoDB服务命令如下: 


systemctl start mongod.service

此时如果没有报错,则表示MongoDB已经启动了,查看MongoDB运行状态的命令如下: 


systemctl status mongod.service

可以看到此时MongoDB已经正常运行了,如图346所示。


图346MongoDB的运行状态


接下来安装MongoDB Shell,再回到MongoDB下载页面,此时修改Available Downloads面板中的Package选项选择shell(rpm),如图347所示。


图347选择shell(rpm)


然后单击Copy Link连接复制shell(rpm)包下载网址,其下载网址为https://repo.mongodb.org/yum/redhat/7/mongodborg/4.4/x86_64/RPMS/mongodborgshell4.4.41.el7.x86_64.rpm,回到CentOS下载包,执行命令如下: 


wget -i -c https://repo.mongodb.org/yum/redhat/7/mongodb-org/4.4/x86_64/RPMS/mongodb-org-shell-4.4.4-1.el7.x86_64.rpm

等待下载完毕后会获得一个名为mongodborgshell4.4.41.el7.x86_64.rpm的文件,安装该文件的命令如下: 


yum -y install mongodb-org-shell-4.4.4-1.el7.x86_64.rpm

等待文件安装完毕后,即可运行MongoDB Shell了,进入Shell的命令如下: 


mongo

显示所有数据库命令如下: 


show dbs



#输出结果为

admin0.000GB

config0.000GB

local0.000GB

至此完成了MongoDB在Linux系统上的安装。因本书主要讲解Python编程语言,所以不再详细展开,如需对MongoDB进行进一步的设置,则可参考MongoDB官方文档。
3.4.4MongoDB可视化工具
因为在安装MongoDB时勾选了Install MongoDB Compass选项,所以在安装程序运行完后会弹出MongoDB Compass界面,MongoDB Compass是MongoDB官方提供的免费的可视化工具。初次打开MongoDB Compass会弹出Privacy Settings选项卡,即隐私设置选项卡,如图348所示。


图348MongoDB Compass隐私设置


该界面显示的大意为“为了增强用户体验,Compass需要与外部网络的第三方服务集成请求。请从下面的设置中选择。”
(1) Enable Product Feedback Tool: 允许向开发团队发送反馈信息。
(2) Enable Geographic Visualizations: 启用地理可视化。
(3) Enable Crash Reports: 允许发送错误报告。
(4) Enable Usage Statistics: 允许发送匿名的使用统计信息。
(5) Enable Automatic Updates: 启动自动更新。
可以根据自身情况选择需要开启或者关闭的信息,在这里笔者选择允许所有选项,然后单击Start Using Compass按钮即可开始使用MongoDB Compass。
单击左侧菜单中的New Connection按钮,用来连接MongoDB服务器,此时MongoDB Compass界面上默认采取的是字符串的连接方式,对于刚接触MongoDB的读者来讲这样的连接方式看上去会有点陌生,可以单击Fill in connection fields individually链接切换到通过填写参数的方式来连接MongoDB服务器,如图349所示。


图349切换至填写参数的模式


该界面包含两个Tab选项,分别为Hostname与More Options,Hostname包含了Hostname、Port、SRV Record及Authentication参数。其中Hostname表示要连接的MongoDB服务器地址,默认为localhost,即为本机。Port表示要连接的MongoDB服务器的端口,MongoDB的默认端口号为27017。SRV Record表示使用SRV的方式进行连接,选择此处后,Hostname需要填写SRV字符串,而不能使用IP地址了,否则会提示URI does not have hostname, domain name and tld错误。Authentication表示使用的加密方式,当前MongoDB的加密方式有5种,分别为Username/Password、SCRAMSHA256、Kerberos、LDAP、X.509,其中Username/Password、SCRAMSHA256是项目中使用得比较多的验证方式。之前的安装没有设置MongoDB的权限,所以此处Authentication选择None。
More Options中包含了Replica Set Name、Read Preference、SSL、SSH Tunnel参数,其中Replica Set Name表示副本集的名称。Read Preference为读取的首选项,可用于设置数据库的读写分离,以及故障转移等操作。该参数下有Primary(主节点)、Primary Preferred(首选主节点)、Secondary(从节点)、Secondary Preferred(首先从节点)、Nearest(邻近节点)几个选项。SSL参数为MongoDB的网络通信进行加密,其包含4种方式,System CA/Atlas Deployment、Server Validation、Server and Client Validation、Unvalidated。SSH Tunnel参数为通过远程服务器连接MongoDB服务器,该参数包含2个选项,分别为Use Password与Use Identity File。
因为连接的是本机的MongoDB单例服务器,所以More Options无须进行配置,Hostname使用默认设置即可,单击Connect按钮连接到本机的MongoDB服务器,如图350所示。



图350连接已安装的MongoDB服务器


单击CREATE DATABASE按钮后可创建新的数据库,在Database Name参数下输入newdatabase,在Collection Name参数下输入newcollection。Capped Collection参数用于设置为固定集合。固定集合的意思是性能出色,有固定大小的集合。当集合空间使用完后,再插入的数据将会从第1条数据开始覆盖,此处无须勾选固定集合。Use Custom Collation参数为使用用户自定义的方式进行排序,此处无须勾选,如图351所示。单击CREATE DATABASE按钮就完成了MongoDB的数据库的创建。


图351创建MongoDB数据库


在MongoDB Compass默认界面可以看到刚才创建的数据库newdatabase,单击newdatabase链接,进入Collections界面可以看到刚才创建的newcollection。继续单击newcollection链接即可进入newcollection集合内,在此可以添加任何类型的数据。单击ADD DATA添加一条新数据,在ADD DATA下有两个选项,分别为Import File与Insert Document。Import File从文件导入数据,支持JSON与CSV两种格式。Insert Document则直接在MongoDB Compass中添加数据,此处选择Insert Document,单击Insert Document按钮进入添加数据页面,如图352所示。在VIEW处选择列表视图,将鼠标移动到_id字段之上,在前方会出现一个加号+按钮,单击加号按钮便可以添加一个新的字段。


图352添加Document


使用此方法在newcollection中插入两条数据,如表33所示。



表33添加的内容



字段名agename

数据124jack

数据230marry

类型Int32String

将上面内容添加到集合中后,在MongoDB Compass界面的newcollection集合下就可以看到添加的两条内容了,如图353所示。


图353已添加的内容


在当前页有3种视图选项按钮,分别是列表式、结构式及表格式,可以根据自身习惯选择不同的表现样式。对于列表式与结构式两种表现样式,当鼠标移动到内容上时,即会弹出功能菜单列表,包括编辑、复制、克隆及删除。对于表格式,功能菜单直接显示在每行内容的最后面,使用功能菜单可以非常方便地对数据进行编辑、复制、克隆及删除。



6min

3.4.5MongoDB基础
1. MongoDB数据库与集合
MongoDB与MySQL虽然属于不同类型的数据库,MongoDB为非关系型数据库,MySQL为关系型数据库,但是在概念上却极为相似,在MongoDB中同样有数据库的概念,其他诸如集合、文档、字段、索引等对于MySQL都有一一对应的概念,具体如表34所示。MongoDB内可存储多个数据库,每个数据库可包含多个集合,而每个集合又可以包含多个文档。


表34MongoDB与MySQL对应的概念



mysqlmongodb说明

databasedatabase数据库

tablecollection数据表/集合

rowdocument记录行/文档

columnfield字段

indexindex索引

primary keyprimary key主键,MongoDB自动将_id字段设置为主键

2. MongoDB格式及数据类型
MongoDB文档支持JSON与BSON两种数据格式,JSON(JavaScript Object Notation)是一种轻量的数据交换格式,因为轻量,因此它易于理解、易于解析、易于记忆,但JSON的数据类型有限,只有null、布尔型、数字、字符串、数组及对象这几种类型,所以JSON有一定的局限性。JSON通常的格式代码如下: 


{

"user": "jack",

"pass": "123456",

"address": [{

"city": "wuhan",

"code": "434000",

"tel": "123456"

}]

}

BSON(Binary Serialized Document Format)也是一种数据交换格式,主要用于MongoDB数据库中的数据存储和网络传输,它是一种二进制表示形式。相较于JSON,BSON支持的数据类型更加丰富,且BSON主要用于提高存储和扫描效率。BSON常见格式代码如下: 


{

user:"jack",

pass:"123456",

nowday: new Date('Jun 23, 2021'),

otherday: new Date('Jun 07, 2022'),

address:{

city:"wuhan",

tel:"123456",

code:434000

} ,

scores:[

{"name":"english","grade:3.0},

{"name":"chinese","grade:2.0}

]

}

MongoDB将数据记录存储为BSON文档,BSON文档由一个有序的元素列表构成。每个元素由一个字段名、一种类型和一个值组成,字段名为字符串。BSON类型如表35所示。


表35MongoDB的数据类型



类型说明

Array数组类型

Binary二进制类型

Boolean布尔类型

Date定长字符串,最大长度为255字节

Decimal128128位IEEE 7542008浮点数;  Binary Integer Decimal的变体

Double浮点数

Int3232位整数

Int6464位整数

MaxKey最大值
续表


类型说明

MinKey最小值

NullNull

Object对象

ObjectIdID对象

BSONRegExpBSON正则表达式

String字符串类型

BSONSymbol符号

BSONMapMap

Timestamp时间戳

UndefinedUndefined

BSON内没有自增字段,自增需要通过代码实现,且BSON文档的最大大小为16MB字节,最大文档的大小有助于确保单个文档不能使用过多的内存,或者在传输期间不能使用过多的带宽。为了存储大于最大大小的文档,MongoDB提供了GridFS API。
在MongoDB文档内有一个特殊的字段为_id,该字段默认由MongoDB自动生成,该字段具有唯一性,且默认被设置为主键。该字段总是文档中的第1个字段,如果服务器首先接收到一个没有_id字段的文档,则服务器将把该字段移到开头。_id字段可以包含除数组之外的任何数据类型的值。
MongoDB创建的默认_id通常为6065400d182c9cf6587975dc样式,该字段中包含了24位十六进制数,也就是12字节(每字节由2个十六进制数组成),6065400d182c9cf6587975dc对应的划分如表36所示。


表36ObjectID的划分



6065400d182c9cf6587975dc

时间戳机器码PID计数器

时间戳也就是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,机器码则表示运行MongoDB的计算机,PID表示生成次_id的进程,计数器是由一个随机开始的计数器生成的值。MongoDB通过如此复杂的生成方式,既可以保证_id字段的唯一性,又可以通过该字段所包含的含义进行查询及排序,非常方便。也可以根据自己的需要定制符合需求的生成规则。


21min

3.5MongoDB操作语法
打开MongoDB Compass,在界面左下角有一个MongoSH Beta链接,单击该链接即可进入MongoDB Shell,如图354所示。


图354打开MongoDB Compass中的MongoSH Beta


MongoDB除了可以使用MongoDB Compass可视化操作以外,还有很多命令的操作方式,该方式可以在MongoDB Shell下执行,且其他语言使用MongoDB时也可以通过调用命令的方式对MongoDB进行操作。下面的命令都可以在MongoSH Beta中执行。
1. 创建数据库
创建一个新的MongoDB数据库newdt的代码如下: 


use newdt



#输出结果为'switched to db newdt'

上面的代码可以用于创建一个名为newdt的新数据库。注意,如果newdt已经存在,则直接使用原数据库而不再创建新数据库。
可以使用db命令查看当前数据库的名称,代码如下: 


db



#输出结果为newdt

如果想查看所有的数据库,则可以使用show dbs命令来查看,代码如下: 


show dbs



#输出结果为

admin65.5 kB

config98.3 kB

local73.7 kB

newdatabase65.5 kB

刚才创建了新的数据库后,不论是使用show dbs命令还是在Mongo Compass内并没有显示刚创建的数据库newdt,因为该数据库内没有数据,如果想显示它,需要向该数据库内插入一些数据。插入数据的示例代码如下: 


db.newcoll.insert({"name":"jack"})



#输出结果为

{ acknowledged: true,

insertedIds: { '0': ObjectId("606569d2aa45a9378c309883") } }

单击MongoDB Compass界面上的刷新按钮,即可看到新创建的数据库newdt,如图355所示。


图355显示新创建的数据库


使用show dbs来查看,则会显示出创建的数据库newdt,代码如下: 


show dbs



#输出结果为

admin65.5 kB

config111 kB

local73.7 kB

newdatabase65.5 kB

newdt73.7 kB

2. 删除数据库
删除数据库的语法格式如下: 


db.dropDatabase()

删除某个数据库前,需要先使用该数据库,即use 数据库名,然后使用删除命令。例如将前面创建的newdt数据库删除,先切换至该数据库,代码如下: 


use newdt



#输出结果为'switched to db newdt'

执行删除命令,代码如下: 


db.dropDatabase()



#输出结果为{ ok: 1, dropped: 'newdt' }

单击MongoDB Compass上的刷新按钮,则看不见数据库newdt了,如图356所示。使用show dbs命令来查看,也看不见newdt了,代码如下: 


show dbs



#输出结果为

admin65.5 kB

config111 kB

local73.7 kB

newdatabase65.5 kB

数据库被删除后,其内的集合及文档都将一并被删除,删除数据库是比较危险的操作,在删除数据库前最好做好备份,以防不测。


图356删除数据库


3. 创建集合
MongoDB中使用createCollection()方法来创建集合,其语法格式如下: 


db.createCollection(name, options)

其中,name为要创建的集合的名称,options为可选参数。options包含的参数如表37所示。


表37删除数据库



参数类型说明

cappedboolean如需创建固定集合,则该参数需设置为true且需要设置size参数的大小

autoIndexIdboolean3.2版本后不再支持该参数。当设置为false时,禁止对_id字段自动创建索引

sizenumber指定固定集合的最大字节数

maxnumber指定固定集合中的最大文档数

storageEnginedocument仅支持WiredTiger存储引擎,允许用户配置存储引擎

validatordocument验证器,允许用户为集合指定验证规则

validationLevelstring指定MongoDB在更新过程中对现有文档验证规则的严格程度

validationActionstring对无效文档的提示形式

indexOptionDefaultsdocument创建集合时为索引指定默认的配置

viewOnstring源collection或源视图,指定依赖某个集合或视图而建的

pipelinearray聚合管道,作为聚合管道片段的一部分,参与聚合操作

collationdocument指定集合的默认排序规则

writeConcerndocument写安全机制,用于控制写入安全的级别

使用createCollection()方法在新创建的数据库newdt中创建一个新的集合newcoll,代码如下: 


use newdt

db.createCollection("newcoll")



#输出结果为{ ok: 1 }

此时已经完成了集合newcoll的创建,在MongoDB Compass内单击“刷新”按钮即可看到刚创建的数据库newdt及数据库内的集合newcoll。
也可以使用options参数创建一个固定集合,示例代码如下: 


use newdt

db.createCollection("newcoll2",{capped:true,size:6000000,max:10000})



#输出结果为{ ok: 1 }

此时创建了一个固定集合,集合的最大字节数为6000000,最大文档数为10000。在MongoDB Compass内单击“刷新”按钮即可看到刚才创建的固定集合newcoll2。固定集合的意思是集合的大小被固定了,当集合空间使用完以后,再插入文档将会从第1条文档开始进行覆盖,如果指定了最大文档数,则同样当插入的文档数量超过了最大文档数,将会从第1条文档开始进行覆盖。固定集合就好比一个圆环,当空间使用完了以后,又回到起点。
4. 删除集合
使用drop()方法来删除集合,其语法格式如下: 


db.集合名称.drop()

例如要删除newdt数据下的newcoll2集合,代码如下: 


use newdt

db.newcoll2.drop()



#输出结果为true

5. 查看所有集合
使用show collections命令查看当前数据库下的所有集合,示例代码如下: 


use newdt

db.createCollection("newcoll3")

show collections



#输出结果为

newcoll3

newcoll

6. 插入文档
使用insert()方法来插入文档,insert()方法既可以插入单条文档,也可以插入多条文档。
其语法格式如下: 


db.collection.insert(

<document or array of documents>, 

{

writeConcern: <document>, 

ordered: <boolean> 

}

)

document为要插入的文档。writeConcern为写入策略,默认值为1,即要求确认写操作,当参数值为0时表示不要求确认写操作。ordered指定是否按顺序写入,默认值为true,即按顺序写入。
若插入的数据主键已经存在,则会抛出org.springframework.dao.DuplicateKeyException 异常,提示主键重复,不保存当前数据。
在newdt数据库中的newcoll集合中插入单条文档,示例代码如下: 


use newdt

db.newcoll.insert({

name:"jack",




age:23,

address:{

city:"wuhan",

code:434000,

tel:123456

}

})



#输出结果为

{ acknowledged: true,

insertedIds: { '0': ObjectId("60658a16aa45a9378c309887") } }

在newcoll集合中插入多条文档,示例代码如下: 


use newdt

db.newcoll.insert([{

name:"tom",

age:23,

address:{

city:"hangzhou",

code:310000,

tel:123456

}

},{

name:"marry",

age:23,

address:{

city:"shanghai",

code:200000,

tel:123456

}

}])



#输出结果为

{ acknowledged: true,

insertedIds: 

{ '0': ObjectId("60658efaaa45a9378c309888"),

'1': ObjectId("60658efaaa45a9378c309889") } }

单击MongoDB Compass的刷新按钮,然后单击newcoll集合就可以看到刚才添加的集合了,如图357所示。


图357插入新的文档


7. 更新文档
使用updateOne()方法来更新单个文档,updateOne()方法在查询条件中即使查询到了满足该条件的多个文档,也只会更新第1个文档,它只用于更新单个文档。updateOne()方法的语法格式如下: 


db.collection.updateOne(

<filter>,

<update>,

{

upsert: <boolean>,

writeConcern: <document>,

collation: <document>,

arrayFilters: [ <filterdocument1>, ... ],

hint:  <document|string>        //Available starting in MongoDB 4.2.1

}

)

filter为查询条件,可以使用与find()方法中相同的查询选择器,类似SQL的WHERE语句。update为要应用的修改。upsert为可选参数,如果设置为true,则在没有文档符合查询条件时创建新的文档,默认值为false。multi为可选参数,用于更新满足条件的全部文档。writeConcern为可选参数,表示写入策略,默认值为1。collation为可选参数,表示排序规则。arrayFilters为可选参数,用于筛选文档的数组,确定要为数组字段上的更新操作修改哪些数组元素。hint为可选参数,指定用于支持查询断言的索引的文档或者字符串。
在前文已经向newcoll集合插入了两个文档,对应于name字段分别为tom与marry,现将tom的city修改为shenzhen,示例代码如下: 


use newdt

db.newcoll.updateOne(

{"name":"tom"},

{$set:{"address.city":"shenzhen"}}

)



#输出结果为




{ acknowledged: true,

insertedId: null,

matchedCount: 1,

modifiedCount: 1,

upsertedCount: 0 }

使用updateMany()方法可更新所有满足条件的文档,updateMany()方法与updateOne()方法格式和参数都一致,唯一不同的是即使updateOne()方法查询到了多个符合查询条件的文档,也只会更新第1个,而updateMany()方法则更新全部的文档。
前文向newcoll添加的所有文档,其age字段均为23,以此为条件将age为23的所有文档中的city修改为beijing,示例代码如下: 


use newdt

db.newcoll.updateMany(

{"age":23},

{$set:{"address.city":"beijing"}}

)



#输出结果为

{ acknowledged: true,

insertedId: null,

matchedCount: 3,

modifiedCount: 3,

upsertedCount: 0 }




注意新版本的MongoDB已经弃用了update()方法,但为了兼容性目前仍然可以使用。建议新开发的程序不要再使用update()方法,更新单个文档使用updateOne()方法,更新多个文档则应使用updateMany()方法,而save()方法也在4.2版本以后被弃用,可以使用replaceOne()方法来代替。




8.  删除文档
使用deleteOne()方法从数据集中删除一个文档,deleteOne()方法的语法格式如下: 


db.collection.deleteOne(

<filter>,

{

writeConcern: <document>,

collation: <document>,

hint: <document|string>//Available starting in MongoDB 4.4

}

filter为删除条件。writeConcern为可选参数,表示写入策略。collation为可选参数,表示排序规则。hint为可选参数,指定用于支持查询断言的索引的文档或者字符串。
使用deleteOne()方法删除newcoll集合中name为tom的文档,代码如下: 


use newdt

db.newcoll.deleteOne({"name":"tom"})



#输出结果为{ acknowledged: true, deletedCount: 1 }

使用deleteMany()删除所有符合条件的文档,其语法格式如下: 


db.collection.deleteMany(

<filter>,

{

writeConcern: <document>,

collation: <document>

}

)

如果要删除数据集下的所有文档,则可以传递一个空的文档给filter。示例代码为删除所有符合age等于23的文档,代码如下: 


use newdt

db.newcoll.deleteMany({"age":23})



#输出结果为{ acknowledged: true, deletedCount: 2 }




注意新版本的MongoDB已经弃用了remove()方法,但为了兼容性目前仍然可以使用。建议新开发的程序不要再使用remove()方法,删除单个文档使用deleteOne()方法,删除多个文档则应使用deleteMany()方法。




9.  查询文档
使用find()方法查询,find()方法的语法格式如下: 


db.collection.find(query,projection)

query为可选参数,表示查询条件。projection为可选参数,用于指定要在文档中返回的与查询条件匹配的字段。如要返回全部字段,则忽略此参数。
下面示例代码将三条文档插入newcoll数据集中,代码如下: 


db.newcoll.insert([{

name:"tom",

age:23,

address:{

city:"hangzhou",

code:310000,

tel:123456

}

},{




name:"marry",

age:23,

address:{

city:"shanghai",

code:200000,

tel:123456

}

},{

name:"jack",

age:23,

address:{

city:"beijing",

code:100000,

tel:123456

}

}

])



#输出结果为

{ acknowledged: true,

insertedIds: 

{ '0': ObjectId("6065adfeaa45a9378c30988b"),

'1': ObjectId("6065adfeaa45a9378c30988c"),

'2': ObjectId("6065adfeaa45a9378c30988d") } }

使用find()方法将所有的文档查询出来,示例代码如下: 


db.newcoll.find()



#输出结果为

{ _id: ObjectId("6065adfeaa45a9378c30988b"),

name: 'tom',

age: 23,

...

也可以使用条件参数将满足条件的文档查询出来,例如查询city为beijing的文档,代码如下: 


db.newcoll.find({"address.city":"beijing"})



#输出结果为

{ _id: ObjectId("6065adfeaa45a9378c30988d"),

name: 'jack',

age: 23,

address: { city: 'beijing', code: 100000, tel: 123456 } }

通过使用不同的查询条件,使查询变得灵活而强大,可以从不同的文档内查询到各种符合查询条件的数据,查询条件有多种匹配的运算符,具体的运算符如表38所示。


表38查询运算符



运算符说明

$eq等于

$gt大于

$gte大于或等于

$in匹配数组中的任意值

$lt小于

$lte小于或等于

$ne不等于

$nin不匹配数组中的任意值

$and与

$not取反

$nor或非

$or或

$exists匹配具有指定字段的文档

$type匹配指定类型字段

$expr聚合表达式

$jsonSchema根据给定的JSON模式验证文档

$mod对字段值执行模运算,并选择具有指定结果的文档

$regex选择与正则表达式匹配的文档

$text执行文本搜索

$where匹配满足JavaScript表达式的文档

$geoIntersects选择与几何图形相交的集合图形

$geoWithin选择便捷几何中的几何

$near返回点附近的地理空间对象

$nearSphere返回球体上某一点附近的地理空间对象

$all匹配包含查询中指定的所有元素的数组

$elemMatch匹配数组字段中元素匹配所有指定的$elemMatch条件

$size匹配数组字段为指定大小

$bitsAllClear匹配数值或二进制值,其中一组比特位置的值都为0

$bitsAllSet匹配数值或二进制值,其中一组比特位置的值都为1

$bitsAnyClear匹配数值或二进制值,其中一组比特位置中的任意位的值都为0

$bitsAnySet匹配数值或二进制值,其中一组比特位置中的任意位的值都为1

常见运算符查询条件的示例代码如下: 


#查询满足name为tom或者age等于23的文档

db.newcoll.find({$or:[{"name":"tom"},{"age":23}]})



#查询age小于40的文档

db.newcoll.find({"age":{$lt:40}})



#查询name为tom同时age等于23的文档

db.newcoll.find({"name":"tom","age":23})





#查询存在age字段且age字段在20~40的文档

db.newcoll.find({"age":{$exists:true,$nin:[20,40]}})

3.6使用Python操作MongoDB
3.6.1MongoDB操作模块

MongoDB官方提供了Python操作MongoDB的驱动PyMongo,MongoDB官方也推荐使用PyMongo来对MongoDB进行操作。不同版本的PyMongo支持的MongoDB版本也不一样,如表39所示,此表为PyMongo对应支持的MongoDB版本。如果下载了旧版本的PyMongo,对于新版本的MongoDB可能无法支持。
前文下载并安装的MongoDB版本为4.4.4版本,根据表39所示,要想对该版本的MongoDB进行正常操作,则需要安装3.11及以上的PyMongo版本才能正常使用。


表39不同版本的PyMongo对MongoDB的支持



Python
DriverMongo
DB 4.4Mongo
DB 4.2Mongo
DB 4.0Mongo
DB 3.6Mongo
DB 3.4Mongo
DB 3.2Mongo
DB 3.0Mongo
DB 2.6

3.11√√√√√√√√

3.1√√√√√√√

3.9√√√√√√√

3.8√√√√√√

3.7√√√√√√

3.6√√√√√

3.5√√√√

3.4√√√√

3.3√√√

3.2√√√

3.1√√

3√√

2.9√√

2.8√√

2.7√

使用pip可以很方便地安装PyMongo,打开PyCharm编辑器,然后单击View→Tool Windows→Terminal打开终端窗口,在命令行中输入pip install pymongo并按回车键来安装PyMongo模块,等待提示Successfully installed pymongo后即可使用。
PyMongo中使用MongoClient()方法来连接MongoDB服务器,连接MongoDB服务器的语法格式如下: 


MongoDB://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]

连接MongoDB服务器并将该服务器上所有的数据库名列出来,其Python代码如下: 


#第3章//mon.py

import pymongo#导入pymongo



#使用MongoClient()方法连接MongoDB服务器

myclient=pymongo.MongoClient("mongodb://localhost:27017/")



#使用list_database_names()方法获取所有数据库名

dblist=myclient.list_database_names()

print(dblist)



#输出结果为['admin', 'config', 'local', 'newdatabase', 'newdt']

3.6.2使用Python操作MongoDB
1. 创建数据库
在MongoDB的命令行模式中创建数据库,可在连接服务器后,使用“use新数据库名”命令即可创建新的数据库,在Python中同样使用此方法来创建数据库,Python创建MongoDB数据库的代码如下: 


import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")

mydb=myclient["pydatabase"]#创建一个名为pydatabase的数据库

当数据库中没有内容时,不会显示该数据库,所以此时使用list_database_names()方法也是无法获取刚创建的数据库。可以在数据库内创建一个集合,并且插入一个文档,这样就可以看到新创建的数据库了,Python中创建集合与创建数据库一样非常简单,创建集合的代码如下: 


#第3章//mon.py

import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")

mydb=myclient["pydatabase"]#创建一个名为pydatabase的数据库

mycoll=mydb["mycoll"]#创建一个名为mycoll的集合

doc={"name":"jack","age":24}#定义一个文档

result=mycoll.insert_one(doc)#将文档插入集合

dblist=myclient.list_database_names()#获取数据库列表

print(dblist)



#输出结果为['admin', 'config', 'local', 'newdatabase', 'newdt', 'pydatabase']

在上面的代码中,mydb=myclient["pydatabase"]表示如果pydatabase数据库存在,则不创建新的数据库,如果pydatabase数据库不存在,则创建新的数据库并命名为pydatabase。
2. 查看数据库
使用list_database_names()方法来查看当前所有的数据库,list_database_names()方法会返回一个列表,列表内为当前所有可以显示的数据库的名称,示例代码如下: 


import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")

dblist=myclient.list_database_names()#查看当前所有数据库

print(dblist)



#输出结果为['admin', 'config', 'local', 'newdatabase', 'newdt', 'pydatabase']

3. 删除数据库
使用drop_database(name_or_database,session=None)方法可删除MongoDB数据库,删除数据库后,数据库内的数据也会一并删除,在实际操作中需谨慎使用该方法。该方法包含两个参数,name_or_database参数为要删除的数据库实例,session为会话。删除pydatabase数据库的示例代码如下: 


#第3章//mon.py

import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")

dblist=myclient.list_database_names()

print(dblist)

dropDatabase=myclient["pydatabase"]

myclient.drop_database(dropDatabase)#删除数据库

dblist=myclient.list_database_names()

print(dblist)



#输出结果为

['admin', 'config', 'local', 'newdatabase', 'newdt', 'pydatabase']

['admin', 'config', 'local', 'newdatabase', 'newdt']

4. 创建集合
使用Python创建集合与创建数据库一样非常简单,示例代码如下: 


import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")

mydb=myclient["pydatabase"]#创建一个名为pydatabase的数据库

mycoll=mydb["mycoll"]#创建一个名为mycoll的集合

在上面的代码中使用数据库对象即可创建一个集合,mycoll=mydb["mycoll"]该段代码创建了一个名为mycoll的集合。
5. 查看集合
使用list_collection_names()方法可查看当前数据库下所有的集合,返回值为列表(list)类型,列表中的值为集合的名称。示例代码如下: 


import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")

mydb=myclient["pydatabase"]#pydatabase数据库已存在,使用pydatabase数据库




listcoll=mydb.list_collection_names()#查看当前数据库下所有的集合

print(listcoll)



#输出结果为['mycoll']

6. 删除集合
使用drop()方法可删除当前集合,示例代码如下: 


import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")

mydb=myclient["pydatabase"]#pydatabase数据库已存在,使用pydatabase数据库

coll=mydb["mycoll"]

coll.drop()#删除当前集合

listcoll=mydb.list_collection_names()

print(listcoll)



#输出结果为[]

7. 插入文档
使用insert_one()方法可插入单个文档,使用insert_id返回插入的_id示例代码如下: 


#第3章//mon.py

import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")

mydb=myclient["pydatabase"]#使用pydatabase数据库

mycoll=mydb["mycoll"]#创建一个名为mycoll的集合

doc={"name":"jack","age":24}#构造一个文档

result=mycoll.insert_one(doc)#插入单个文档

id=result.inserted_id#返回刚才插入文档的_id

print(id)



#输出结果为6066838efd04788beb0f6b15

使用insert_many()方法可插入多个文档,使用inserted_ids返回所有插入文档的id值,示例代码如下: 


#第3章//mon.py

import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")

mydb=myclient["pydatabase"]#使用pydatabase数据库

mycoll=mydb["mycoll"]#使用mycoll的集合

arraydoc=[

{"name":"jack","age":24},

{"name":"tom","age":25},

{"name":"marry","age":26},

{"name":"jan","age":27},

]

#构造文档列表




results=mycoll.insert_many(arraydoc)#插入多条文档

ids=results.inserted_ids#返回id列表

print(ids)



#输出结果为

[ObjectId('6066855cec0a22b64766563f'), 

ObjectId('6066855cec0a22b647665640'), 

ObjectId('6066855cec0a22b647665641'), 

ObjectId('6066855cec0a22b647665642')]

对于_id,除了可以使用系统生成的_id字段以外,也可以插入指定_id的文档。例如要插入一条指定_id字段的文档,示例代码如下: 


#第3章//mon.py

import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")

mydb=myclient["pydatabase"]

mycoll=mydb["mycoll"]

doc={"_id":12345,"name":"jack","age":24}#构造一个指定_id的文档

result=mycoll.insert_one(doc)

id=result.inserted_id

print(id)



#输出结果为12345

8.  更新文档
使用update_one()方法更新单条文档,该方法常用两个参数,filter与update,filter参数表示要更新文档的查询条件,update表示要更新的文档,与MongoDB的Shell命令一致,update_one即使查询出多条符合条件的文档,也只会更新第1条文档。示例代码如下: 


#第3章//mon.py

import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")

mydb=myclient["pydatabase"]

mycoll=mydb["mycoll"]

query={"_id":12345}#要更新文档的查询条件

doc={"$set":{"name":"jack_update","age":99}}#需要更新的字段

result=mycoll.update_one(query,doc)#更新一条文档

使用update_many()方法可更新所有匹配条件的文档,该方法常用的两个参数为filter与update,filter参数表示要更新文档的查询条件,update表示要更新的文档。示例代码如下: 


#第3章//mon.py

import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")

mydb=myclient["pydatabase"]





mycoll=mydb["mycoll"]

query={"_id":12345}#要更新文档的查询条件

doc={"$set":{"name":"jack_update","age":99}}#需要更新的字段

result=mycoll.update_many(query,doc)#更新所有满足查询条件的文档

9.  查询文档
使用find_one()方法可查询集合中满足条件的一条文档,find_one()方法的主要参数为filter,即查询条件,find_one()方法查询的条件即使有多条文档满足,也只会返回一条文档数据,其示例代码如下: 


#第3章//mon.py

import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")

mydb=myclient["pydatabase"]

mycoll=mydb["mycoll"]

query={"_id":12345}#查询条件

result=mycoll.find_one(query)#查询一条文档

print(result)



#输出结果为{'_id': 12345, 'name': 'jack_update', 'age': 99}

使用find()方法可查询集合中所有满足条件的文档,find()方法的主要参数为filter,即查询条件,使用find()方法查询所有age小于40的文档,示例代码如下: 


#第3章//mon.py

import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")

mydb=myclient["pydatabase"]

mycoll=mydb["mycoll"]

query={"age":{"$lt":40}}#查询所有age小于40的文档

result=mycoll.find(query)

for cur in result:

print(cur)



#输出结果为

{'_id': ObjectId('6066818c74814628cc9a0...

匹配查询的运算符在前文MongoDB操作语法内已经讲解过,如有对匹配运算符不清楚的读者可以翻看前文。需要注意的是,在MongoDB 的Shell中使用find()方法其运算符是不需要加引号的,但是在Python中运算符需要使用引号括起来。find()方法查询的结果为pymongo.cursor.Cursor,可以循环将字典对象也就是文档读取出来。
使用limit()设置返回find()查询的指定条数,该方法接收一个数字参数。如设置的指定条数大于find()返回的总条数,则按find()返回条数显示,示例代码如下: 


#第3章//mon.py

import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")




mydb=myclient["pydatabase"]

mycoll=mydb["mycoll"]

query={"age":{"$lt":40}}#查询所有age小于40的文档

result=mycoll.find(query).limit(2)#限制返回2条文档

for cur in result:

print(cur)



#输出结果为

{'_id': ObjectId('6066818c74814628cc9a06c4'), 'name': 'jack', 'age': 24}

{'_id': ObjectId('606681a8a1d83301dfbfe9c9'), 'name': 'jack', 'age': 24}

10.删除文档
使用delete_one()方法可删除匹配条件的文档,该方法常用的参数为filter,即匹配查询条件,delete_one()只会删除一条匹配的文档,即使该查询条件匹配出多条文档,也只删除一条文档。例如要删除name为jack的文档,示例代码如下: 


#第3章//mon.py

import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")

mydb=myclient["pydatabase"]

mycoll=mydb["mycoll"]

query={"name":"jack"}#查询name为jack的文档

result=mycoll.delete_one(query)#删除一条匹配的文档

使用delete_many()方法可删除所有匹配条件的文档,该方法常用的参数为filter,即匹配查询条件,例如删除所有age小于20的文档,示例代码如下: 


#第3章//mon.py

import pymongo

myclient=pymongo.MongoClient("mongodb://localhost:27017/")

mydb=myclient["pydatabase"]

mycoll=mydb["mycoll"]

query={"age":{"$lt":"jack"}}#查询所有age小于20的文档

result=mycoll.delete_many(query)

如果要删除集合中内所有的文档,则传入的匹配条件为{}即可。
3.7Redis简介及安装
3.7.1Redis简介

Redis是一个开源(BSD许可)的内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构,如字符串、散列、列表、集合、有序集合与范围查询、bitmaps、hyperloglogs和地理空间(geospatial) 索引半径查询。Redis内置了复制、LUA脚本、LRU驱动事件、事务和不同级别的磁盘持久化,并通过Redis哨兵和自动分区提供高可用性。
Redis执行的是纯内存操作,需要的时候可以持久化到硬盘中,且Redis是单线程,没有频繁的切换操作,数据结构简单,自己构建了VM机制,使用多路I/O复用模型,因为这些特性,所以Redis访问速度非常快。
由于Redis的访问速度快、高可用及支持数据类型丰富等特性,所以被大量地应用在缓存数据、消息队列、计数器、热点数据等请求量巨大且对实时性要求比较高的应用场景中。
3.7.2Redis安装
目前Redis官方已不再提供Windows平台下的Redis版本,且Redis官方推荐部署在Linux操作系统下,所以想要使用Redis则需要在Linux操作系统下进行安装。笔者使用的Linux版本为CentOS 7 64位操作系统。
首先打开Redis的官方网站,网址为https://redis.io/,单击Download链接进入Redis下载页面,如图358所示。


图358Redis下载页面


在Redis下载页面有3个可选下载项,分别为Unstable(不稳定版本)、Stable(稳定版)、Docker Hub(Docker安装版),在笔者写作期间Redis的最新版本为6.2。
单击Stable版本的Download 6.2.1按钮下载Redis安装包,然后将下载好的Redis安装包上传到CentOS操作系统内。也可以在Download 6.2.1按钮上右击,在弹出菜单中选择“复制链接地址”将该安装包的下载链接复制到CentOS操作系统内进行下载,安装包的下载网址为https://download.redis.io/releases/redis6.2.1.tar.gz,进入CentOS操作系统进行下载,执行命令如下: 


wget -i -c https://download.redis.io/releases/redis-6.2.1.tar.gz

下载完后可以得到一个redis6.2.1.tar.gz的压缩包,将其解压出来的命令如下: 


tar -zxf redis-6.2.1.tar.gz

解压完成后即可获得一个与压缩包同名的文件夹,也就是redis6.2.1,进入redis6.2.1文件夹,执行命令如下: 


cd redis-6.2.1

在进行make前,先确认是否安装了gcc,如果没有安装gcc则编译会失败,失败时会提示cc: command not found错误。使用yum命令安装gcc,命令如下: 


yum install gcc

安装gcc,等待出现Complete后执行make命令,命令如下: 


make

有时会出现以下错误,如图359所示。


图359编译Redis时出现的错误


当出现如图359所示的错误时需要在make后加上MALLOC=libc强制对libc malloc进行编译,参数命令如下: 


make MALLOC=libc

Redis安装完毕后会提示Hint: It's a good idea to run 'make test';,安装程序提示我们进行安装测试,输入命令如下: 


make test

执行命令后提示You need tcl 8.5 or newer in order to run the Redis test,使用yum安装tcl,命令如下: 


yum install tcl

安装完tcl后,再次执行make test,命令如下: 


make test

此时一切正常,表示Redis安装完成了,即使make test不通过也不必太过担心,并不影响Redis的使用。Redis安装完成后会在redis6.2.1目录下生成一个src文件夹,里面有3个可执行文件,分别为redisserver、redisbenchmark和rediscli,将这3个文件复制至/usr/redis目录下,再将redis6.2.1目录下的redis.conf也复制至/usr/redis目录下,在src目录内执行的命令如下: 


mkdir /usr/redis

cp redis-server  /usr/redis

cp redis-benchmark /usr/redis

cp redis-cli  /usr/redis

cd ..

cp redis.conf  /usr/redis

此时在/usr/redis目录下就有4个文件了,如图360所示。


图360Redis文件夹中的文件


进入/usr/redis文件夹内,启动Redis的命令如下: 


cd /usr/redis

./redis-server redis.conf

执行上面的命令后,Redis就成功启动了,如图361所示。


图361Redis运行界面


在Redis运行界面中显示当前程序在独立模式下运行,端口号为6379,PID为14019。此时不能将该界面关闭,当前属于前台运行方式,如果关闭了该界面则Redis就停止运行了,接下来将Redis设置为后台运行。
按快捷键Ctrl+C关闭当前运行界面,打开/usr/redis/redis.conf配置文件,命令如下: 


vi /usr/redis/redis.conf

在打开的redis.conf文件内按斜杠键/进行全文检索,在斜杠键后输入daemonize,然后按回车键,此时文档会定位到daemonize no这一行,单击i键进行编辑,通过方向键控制光标的位置,将daemonize后的no修改为yes,然后按ESC键,再键入:wq进行保存,如图362所示。


图362修改Redis配置文件


此时再次启动Redis,Redis欢迎界面就不显示了,执行命令如下: 


cd /usr/redis

./redis-server redis.conf

查看Redis是否运行,代码如下: 


ps -ef | grep redis

此时Redis已经在后台运行了,如图363所示。


图363Redis运行进程


3.7.3Redis可视化工具
不同于MySQL与MongoDB,Redis官方没有提供可视化工具,目前市场上比较流行的且比较完善的Redis可视化工具有RedisDesktopManager与FastoRedis等,这里主要讲解RedisDesktopManager工具的安装及使用。
RedisDesktopManager是一款比较流行的Redis可视化工具,它起初是款开源产品,之后升级成为一款商业软件。其产品官网为https://rdm.dev/。RedisDesktopManager简称RDM,适用于多种平台,是一个用于Windows、Linux和macOS的快速开源Redis数据库管理应用程序。该工具提供了一个易于使用的GUI,可以访问Redis数据库并执行一些基本操作: 将键视为树、CRUD键、通过Shell执行命令。RDM支持SSL / TLS加密。
打开RedisDesktopManager的官网https://rdm.dev/,如图364所示。


图364RDM官网


单击“价钱”链接进入产品试用界面,在Windows平台下有3个订阅计划,分别为个人、企业、Microsoft,单击“开始14天免费试用”按钮进行注册。输入你的邮箱及注册密码,单击“注册”按钮进行注册,此时会向你的邮箱发送一封邮件,如图365所示。单击Confirm Your Email按钮完成邮箱验证。


图365进行邮箱验证


此时会跳转回RDM的官方网站,并会显示一个“开始免费的14天试用”的按钮,单击此按钮就可以进入下载页面进行下载了,如图366所示。下载Windows版本,单击Windows文字右侧的2021.3.332链接即可开始RDM的下载。


图366下载RDM测试版


下载完RDM后双击安装程序便可进行安装,安装过程比较简单,此处略过。安装完毕RDM后,初次启动RDM需要输入邮箱及密码,如图367所示。
将刚才在RDM官网注册的邮箱及密码填入后,单击“登录”按钮即可来到RDM的主界面,如图368所示。此时的RDM没有内容,需要在连接Redis服务器后才可以进行下一步的操作。



图367初次打开RDM界面




图368RDM主界面



使用RMD的第1步就是要连接Redis服务器,前面搭建好的Redis服务所在的服务器IP地址为192.168.3.103,要连接该服务器此时需单击“连接到Redis服务器”按钮,这时会弹出一个窗口,需要对连接的服务器进行设置,如图369所示。


图369RDM连接Redis服务器


如图369所示,需要填写远程服务器的相关参数才能进行连接,包含的参数如下。
名字: 标识符,可以填写中文,用于区分Redis服务器。
地址: Redis服务器的IP地址,因使用SSH的方式进行连接,所以此处填写127.0.0.1,使用SSH方式连接相当于使用远程服务器的用户名及密码登录到远程服务器上对本机的Redis进行连接。
密码: 因未设置Redis的密码,此处留空。
用户名: 因未设置Redis的用户名,此处留空。
SSH地址: 远程服务器的IP地址。
SSH用户: 远程服务器登录的用户名。
密码: 远程服务器登录的密码。
设置好以上参数后,单击“测试连接”按钮,此时RDM就可以连接上远程服务器的Redis服务了,然后单击“确定”按钮对Redis进行连接。此时在RDM的主界面会出现一个Redis的远程连接标识符,单击此标识符就可以看到远程Redis服务器上的所有数据库了,如图370所示。


图370远程Redis服务器的数据库列表


在Redis标识符的右侧,有一排操作按钮,分别是服务器信息、打开控制台、重载服务器、卸载所有数据、编辑连接设置、复制连接及删除连接。
单击“服务器信息”按钮,在RDM界面的右侧会显示当前连接的远程服务器的运行状态信息,如图371所示。在服务器信息界面,包含了全景信息、服务器信息、慢查询日志、客户端及推送/订阅通道等几个栏目。
全景信息: 可以了解当前服务器上每秒查询率、连接的客户端数量、内存占用、网络输入、网络输出及键总量等内容,其内容都有图表的形式实时呈现,该界面可用于监测服务器的性能情况。
(1) 服务器: 在该栏目下可以查看诸如clients、cluster、command、cpu、errorstats、memory、persistence、replication、server、stats等信息。
(2) 慢查询日志: 在该栏目可以查看Redis中的慢查询日志。慢查询日志主要记录了一些执行时间超过给定时长的Redis请求,让使用者更好地监视和找出在业务中的一些慢Redis操作,以便找到更好的优化方法。
(3) 客户端: 在该栏目下可以查看当前连接Redis的客户端IP、时长及当前执行的库。
(4) 推送/订阅通道: 在该栏目下可以查看推送/订阅通道的情况。


图371RDM服务器信息界面


单击“打开控制台”按钮,在RDM界面的右侧会显示当前所连的Redis Shell,如图372所示。可以在该窗口执行Redis的命令,如输入ping,则Redis服务器会返回PONG。


图372RDM控制台


单击“重载服务器”按钮,会重新刷新服务器。单击“卸载所有数据”按钮,会清空所有数据。单击“编辑连接设置”按钮会打开连接配置对话框。单击“复制链接”按钮,会在RDM服务器列表里增加一个与当前连接一模一样的连接。单击“删除连接”按钮则会删除当前连接。
单击db0数据库,在其右侧有个“添加新键”按钮,单击此按钮便可向db0中添加一个键名为session1的键,字段类型为String,字段值为12345,如图373所示。单击“保存”按钮,此时就完成了向Redis中db0数据库添加数据的操作。


图373RDM添加字段


在db0下会多出一个session1的按钮,单击此按钮,在RDM右侧会看到键session1的值为123456,如图374所示。在当前界面可以对键值进行重命名。


图374RDM编辑字段


单击“重命名”按钮即可修改键值名称,在值处可以直接进行修改,修改完后右侧保存按钮便被激活。RDM的整体界面比较简洁,操作也比较方便。
3.7.4Redis基础
Redis是一个开源的高性能键值对(keyvalue)非关系型数据库,属于NoSQL产品类,因其速度快,数据类型丰富,常被用作缓存、消息队列、排行榜、电子商务秒杀等功能应用模块,与MySQL或者MongoDB进行互补。
Redis 6.2支持6种数据类型,其数据类型包括string、list、set、zset、hash、stream。其中string表示字符串类型。list表示列表类型。set表示集合类型。zset表示有序集合类型。hash表示哈希类型。stream表示数据流类型。其中stream类型是Redis 5.0以后新增加的数据类型。其类型的具体说明如表310所示。


表310Redis类型说明



数据类型说明

string(字符串)可存储字符串、整数和浮点数

list(列表)列表,它的每个节点都包含一个字符串

set(集合)无序的集合,在此集合中的每个元素都是一个字符串,且不重复

zset(有序集合)有序集合,可包含字符串、整数、浮点数、分值,排序大小由分值决定

hash(哈希散列)键值对应的无序列表

stream(流)消息链表,每条消息都有唯一的ID和对应的内容

在前面使用RDM时,细心的读者发现了当RDM连接到Redis后,立即显示了16个数据库,编号为0~15,而之前使用MySQL与MongoDB时则不会出现这种情况。在MySQL与MongoDB中,数据库都是由用户自己创建的。
Redis中创建的16个数据库的概念与传统的数据库其实是不太一样的,Redis此时的数据库更像MySQL中表的概念,在MySQL的表中可以存放任何类型的字段和对应的值,而在Redis的db中,同样也存放着字段和值。与其说是数据库,其更像表,如图375所示。


图375Redis数据库与MySQL表对比


至于为什么是16个数据库,这是由Redis的作者所设置的默认配置,此数量可以根据Redis配置文件进行修改,在redis.conf文件中有一行配置信息为databases 16,如果将16修改为1000则Redis启动的时候就会自动创建1000个数据库了。默认创建多个数据库还有另一个原因是为了开发者更好地管理自己的数据,可以将不同功能的数据存放在不同的数据库中以便维护。
Redis不支持自定义数据库名字,所以每个数据库都以编号命名。开发者需要自己记录存储的数据与数据库的对应关系,且Redis不支持为不同的数据库设置不同的密码,客户端要么能访问全部的数据库,要么一个都访问不了。


24min

3.8Redis操作语法
Redis主要有6种类型的数据,而Redis的主要操作都是针对这6种数据类型进行的。以下所有的操作都是在RDM的控制台里进行的。
1. string(字符串)增、删、改、查


#增加一条键为newkey,值为str的记录

set newkey "str"

ok



#查询newkey键的键值

get newkey

"str"



#将newkey键的键值修改为newstr

set newkey "newstr"

ok



#将newkey键的名称修改为nkey

rename newkey nkey

ok



#查找所有给定模式的key

keys n*

"nkey"



#删除指定键

del nkey

"1"



#查询指定键是否存在

exists nkey

"0"



#删除当前数据库中的所有内容

flushdb

ok

2. set(集合)增、删、改、查
操作集合时需要注意的是,集合内的成员是不重复的、唯一的且成员类型是string类型。集合操作代码如下:


#创建一个集合并向其中添加3个成员

sadd setkey "123","abc","你好"

3



#查询指定集合里所有的成员

smembers setkey

"123"

"abc"

"你好"



#删除成员abc,如果有则返回1,如果没有则返回0

srem setkey "abc"

1



#添加不重复成员,重复成员无法添加

sadd setkey "aaa"

1

3. list(列表)增、删、改、查
list列表按照插入顺序排序,列表内容可以向列表的头部或者尾部添加元素,操作代码如下: 


#创建一个3个元素的列表

lpush listkey "123","abc","你好"

3



#查询listkey的集合

lrange listkey 0 -1

"123"

"abc"

"你好"



#向list尾部添加元素

rpush listkey "new"

6



#向list头部添加元素

lpush listkey "lnew"

7



#更新index为1的值

lset listkey 1 "index1"

ok



#删除index为1的值

lrem listkey 1 "index1"

1

4. hash(哈希)增、删、改、查
hash是一个string类型的field和value的映射表,适合存储对象,操作代码如下: 


#创建一个hash集合hashtable,并将key设置为user,将value设置为jack

hset hashtable "user" "jack"

1



#获取hash中字段的数量

hlen hashtable

1



#获取hash中所有的key

hkeys hashtable

"user"



#返回hash中所有的value

hvals hashtable

"jack"



#向hash添加记录

hset hashtable "pass" "123456"

1



#获取指定键的值

hget hashtable user

"jack"



#获取当前hash所有的键与值

hgetall hashtable

"user"

"jack"

"pass"

"123456"



#更新hashtable中user的值

hset hashtable user "123"

0



hgetall hashtable

"user"

"123"

"pass"

"123456"

5. zset(有序集合)增、删、改、查
zset(有序集合)与set(集合)一样,其元素为string类型,且不允许重复成员的出现。与set不同的是zset每个元素都会关联一个score(分数),Redis通过分数来为集合中的成员进行排序。有序集合的成员是唯一的,但score允许相同,操作代码如下: 


#创建一个有序集合并向其中添加一个成员,且将分数设为1

zadd zsetkey 1 "str"

"1"



#向有序集合内再添加一个成员,且将分数设为2

zadd zsetkey 2 "sec"

"1"



#查询有序集合内所有的值

zrange zsetkey 0 -1

1) "str"

2) "sec"



#删除有序集合内的成员

zrem zsetkey "str"

1



#显示有序集合内的所有成员

zrange zsetkey 0 -1

1) "str"

3.9使用Python操作Redis
3.9.1Redis操作模块

Redis官方没有提供Python语言的操作模块,但是市场上有大量由第三方开发的Python模块,Redis官方也将这些第三方模块收集并公示在其官方网站上了。Redis的官方网站为https://redis.io,打开其官方网站,单击Clients链接即可进入Redis官方收集的针对各种语言的客户端,如图376所示。


图376其他语言对Redis的支持


在该页中Redis官方提示,在其推荐的客户端后标有星星图标。此处单击Python链接便可跳转到Python客户端的列表中,如图377所示。


图377支持Redis的Python客户端列表


在前面Redis官方提示过,推荐使用的客户端后标有黄色小星星,往下滑动Python语言的客户端列表,发现有两个Python客户端被Redis官方推荐,分别为redispy与walrus,如图378所示。


图378Redis官方推荐的Python客户端


对于这两个库Redis官方对其分别描述为,redispy成熟且有支撑,符合目前Python的发展方向。walrus为轻量级Python库。根据以上信息,选择redispy用作Python对Redis的开发会更加合适。
单击redispy黄色小星星右侧的分支图标即可进入redispy的GitHub项目,其链接地址为https://github.com/andymccurdy/redispy,如图379所示。


图379redispy项目的GitHub页面


在redispy项目的说明中提到,redispy 3.5.x将是支持Python 2的最后一个版本,在2020年8月1日之前将继续为Python 2修复错误及提供安全补丁,在这之后将停止对Python 2的支持,而redispy 4.0将是未来的主要版本,且要使用redispy 4.0需要Python 3.5以上的版本。
根据其提示目前redispy 3.5.x为最新版且仍然支持Python 2,但仅提供错误修复及安全补丁,不排除下一个版本可能就不再支持Python 2。在Python 3上是可以正常使用的。redispy可以通过pip进行安装,打开PyCharm并进入终端,使用PyCharm终端安装redispy,其安装命令如下: 


pip install redis

出现Successfully installed redis3.5.3字样即表示安装成功,如图380所示。


图380安装redispy


3.9.2使用Python操作Redis
redispy项目的GitHub页上提到了redis模块提供了两个类,分别是Redis和StrictRedis,redispy 3.0不再支持传统的Redis客户端类,StrictRedis已被重命名为Redis并且提供了一个名为StrictRedis的别名,以便以前使用StrictRedis的用户可以继续运行而不改变代码。redispy不支持集群模式。
1. 连接Redis
如果使用普通连接方式,则需要注意的是应在CentOS操作系统上的防火墙将Redis服务器端口设置对外开放,临时开放命令如下: 


iptables -I INPUT 1 -p tcp -m state --state NEW -m tcp --dport 6379 -j ACCEPT

且将redis.conf中的bind 127.0.0.1 -::1替换为bind 0.0.0.0 -::1,将protectedmode设置为no,否则无法连接Redis。
redis模块下的Redis类构造函数拥有丰富的参数,可以进行多种方式的连接,例如普通连接、SSH连接等,其参数如表311所示。


表311Redis构造函数参数



参数说明

host连接的主机地址

port连接Redis服务的端口

db默认连接Redis数据库

passwordRedis的密码

socket_timeoutsocket超时时间

socket_connect_timeoutsocket连接超时时间

socket_keepalivesocket的长连接

socket_keepalive_optionssocket长连接设置

connection_pool连接池

unix_socket_pathsocket path

encoding编码

encoding_errors错误处理方案

charset字符集

decode_responses返回结果是否为decode

retry_on_timeout重试超时时间

sslssl连接方式

ssl_keyfilessl keyfile

ssl_certfilessl certfile

ssl_cert_reqs设置ssl安全检查模式

ssl_ca_certs证书路径

max_connections最大连接数

single_connection_client单用户连接限制

health_check_interval心跳检测

client_name客户端名称

username用户名

使用Redis进行普通连接Redis服务器的代码如下: 


import redis

r=redis.Redis(host='192.168.3.106', port=6379, db=0)




r.set('foo', 'bar')

print(r.get('foo'))



#输出结果为b'bar'

如需登录跳板机连接Redis服务器,且使用跳板机的用户名和密码登录,需要引入sshtunnel模块,虽然Redis类提供了SSH的连接方式,但是无法使用跳板机的用户名和密码进行验证。首先安装sshtunnel模块,pip命令如下: 


pip install redis

出现Successfully即表示安装成功,sshtunnel模块中有个SSHTunnelForwarder类,该类用于初始化到远程服务器的SSH隧道,其构造函数常用的参数包括ssh_address_or_host(SSH地址)、ssh_username(SSH连接的用户名)、ssh_password(SSH连接的密码)及remote_bind_address(远程机器地址和端口号),使用SSH连接Redis服务器的具体代码如下: 


#第3章//rds.py

import sshtunnel

import redis

server=sshtunnel.SSHTunnelForwarder(

ssh_address_or_host="192.168.3.106",#远程服务器地址

ssh_username="root",#远程服务器登录用户

ssh_password="root",#远程服务器登录密码

remote_bind_address=('192.168.3.106',6379)#远程服务器IP及端口号

)

server.start()

conn=redis.Redis(

host='127.0.0.1', #Redis所在服务器地址

port=server.local_bind_port, #Redis端口

decode_responses=True#返回方式为字符串

)

print("已连接")



#输出结果为已连接

对于新手读者来讲,有个常见的错误需要注意一下,有种情况在使用redis模块时会提示partially initialized module 'redis' has no attribute 'Redis',如图381所示。


图381使用Redis模块报错


这里需要注意了,一是检查import redis是否有拼写错误,二是看一看当前文件名或者同项目下是不是有文件名取了redis.py的名字。
通常在实际使用Redis连接时更偏向于使用连接池进行连接和管理,如果采取直连的方式,使用Redis时要进行连接,不用时又释放了连接,而频繁地连接和释放是比较浪费资源的,所以通常情况下使用连接池的方式进行管理连接,连接池的原理是通过预先创建的多个连接,当进行Redis操作时,直接获取已经创建的连接进行操作,操作完成后不会释放连接,将用于后续其他的Redis操作,这样就达到了避免频繁地对Redis进行连接和释放的目的,从而提高了性能。redis模块采用ConnectionPool来管理对Redis Server的所有连接。连接池连接Redis的代码如下: 


import redis

pool=redis.ConnectionPool(host='localhost', port=6379,db=0)

red=redis.Redis(connection_pool=pool)

red.set('key1', 'value1')

red.set('key2', 'value2')

在SSH模式下使用连接池,代码如下: 


#第3章//rds.py

import redis

import sshtunnel

server=sshtunnel.SSHTunnelForwarder(

ssh_address_or_host="192.168.3.106",

ssh_username="root",

ssh_password="root",

remote_bind_address=('192.168.3.106',6379)

)

server.start()

pool=redis.ConnectionPool(host='127.0.0.1', port=server.local_bind_port,db=0)

red=redis.Redis(connection_pool=pool)

red.set('key1', 'value1')

red.set('key2', 'value2')

2. string(字符串)增、删、改、查


#第3章//rds.py

import redis

pool=redis.ConnectionPool(host='localhost', port=6379,db=0)

red=redis.Redis(connection_pool=pool)



#增加一个key为key1,value为value1的值

red.set('key1', 'value1')



#查询key1的值

red.get("key1")



#修改key1的值

red.set('key1', 'value2')



#将key1的键名修改为key2





red.rename("key1","key2")



#获取所有的键名

red.keys()



#删除key2

red.delete("key2")



#查询key2是否存在

red.exists("key2")



#清空当前数据库中所有的key

red.flushdb()

3. set(集合)增、删、改、查


#第3章//rds.py

import redis

pool=redis.ConnectionPool(host='localhost', port=6379,db=0)

red=redis.Redis(connection_pool=pool)



#创建一个集合并向其中添加3个成员

red.sadd("setkey","123","abc","你好")



#查询指定集合里所有的成员

red.smembers("setkey")



#删除成员abc,如果有则返回1,如果没有则返回0

red.srem("setkey","abc")



#添加不重复的成员,重复的成员无法添加

red.sadd("setkey","aabbcc")

4. zset(有序集合)增、删、改、查


#第3章//rds.py

import redis

pool=redis.ConnectionPool(host='localhost', port=6379,db=0)

red=redis.Redis(connection_pool=pool)



#创建一个有序集合并向其中添加2个成员,且将分数分别设为1和2

mapping={"str":1,"sec":2}

red.zadd("zsetkey",mapping)



#向有序集合内再添加一个成员,且将分数设为2

red.zadd("zsetkey",{"thr":2})



#查询有序集合内所有的值

res=red.zrange("zsetkey",0,-1,withscores=True)#withscores带上分数





for i in res:

print(i)

#输出结果为

(b'str', 1.0)

(b'sec', 2.0)

(b'thr', 2.0)



#删除有序集合内的成员

red.zrem("zsetkey","str")

5. list(列表)增、删、改、查


#第3章//rds.py

import redis

pool=redis.ConnectionPool(host='localhost', port=6379,db=0)

red=redis.Redis(connection_pool=pool)



#创建一个含3个元素的列表

red.lpush("listkey","123","abc","你好")



#查询listkey的集合

res=red.lrange("listkey",0,-1)

for i in res:

print(i)

#输出结果为

b'\xe4\xbd\xa0\xe5\xa5\xbd'

b'abc'

b'123'



#向list尾部添加元素

red.rpush("listkey","new")



#向list头部添加元素

red.lpush("listkey","lnew")



#更新index为1的值

red.lset("listkey",1,"index1")



#删除index为1的值

red.lrem("listkey",1,"index1")

6. hash(哈希)增、删、改、查


#第3章//rds.py

import redis

pool=redis.ConnectionPool(host='localhost', port=6379,db=0)

red=redis.Redis(connection_pool=pool)





#创建一个hash集合hashtable,并将key设置为user,将value设置为jack

red.hset("hashtable","user","jack")



#获取hash中字段的数量

red.hlen("hashtable")



#获取hash中所有的key

red.hkeys("hashtable")



#返回hash中所有的value

red.hvals("hashtable")



#向hash添加记录

red.hset("hashtable","pass","123456")



#获取指定键的值

print(red.hget("hashtable","user"))



#获取当前hash所有的键与值

red.hgetall("hashtable")

#输出结果为{b'user': b'jack', b'pass': b'123456'}



#更新hashtable中user的值

red.hset("hashtable","user","123")

red.hgetall("hashtable")

#输出结果为{b'user': b'123', b'pass': b'123456'}

不论是MySQL、MongoDB还是Redis,Python程序能在其之上良好地运行得益于对数据库本身的特点特性、语法结构及使用方法的掌握,理解了数据库本身的原理、逻辑及使用方法,则立即就可以使用Python对其进行操作,这些Python模块都是根据数据库自身的方法进行构造的,使用起来非常简单和方便。