Python MySQL数据库5:MySQL高级知识&账
总体内容
- 1、视图
- 2、事务
- 3、索引
- 4、账户管理
- 5、MySQL主从同步配置
一、视图
-
1.1、问题?
- 对于复杂的查询,往往是有多个数据表进行关联查询而得到,如果数据库因为需求等原因发生了改变,为了保证查询出来的数据与之前相同,则需要在多个地方进行修改,维护起来非常麻烦
- 解决办法:定义视图
-
1.2、视图是什么
- 通俗的讲,视图就是一条SELECT语句执行后返回的结果集。所以我们在创建视图的时候,主要的工作就落在创建这条SQL查询语句上。
- 视图是对若干张基本表的引用,一张虚表,查询语句执行的结果,不存储具体的数据(基本表数据发生了改变,视图也会跟着改变);顾名思义:也就是视图创建后,如果其他的表发生了变化,视图表也会跟着变,它也是一种表,虚拟的表,只可以查数据,不能 增/删/改。
- 方便操作,特别是查询操作,减少复杂的SQL语句,增强可读性;
-
1.3、定义视图(下面我们以数据库 jing_dong 为例)
-
建议以
v_
开头,增加可读性,语法如下:create view 视图名称 as select语句;
例如:下面语句中 as 后面是 sql语句
视图的创建create view v_goods_info as select g.*,c.name as cate_name,b.name as brand_name from goods as g left join good_cates as c on g.cate_id = c.id left join good_brands as b on g.brand_id = b.id;
-
-
1.4、使用视图:视图的用途就是查询:
执行查询视图表select * from v_goods_info;
,查出的数据和其他连表查询的结果一样
-
1.5、删除视图
drop view 视图名称;
例如:删除上面创建的视图表 v_goods_info
drop view v_goods_info;
-
1.6、当其他表发生变化的时候,视图表也会发生变化,如下,我们修改一下goods表里面
x240 超极本
改为x86 超极本
表发生变化,视图也会跟着变化update goods set name = 'x86 超极本' where name = 'x240 超极本 ';
-
1.7、视图的作用
- 提高了重用性,就像一个函数
- 对数据库重构,却不影响程序的运行
- 提高了安全性能,可以对不同的用户
- 让数据更加清晰
二、事务
-
2.1、为什么要有事务?
事务广泛的运用于订单系统、银行系统等多种场景
例如:A用户和B用户是银行的储户,现在A要给B转账500元,那么需要做以下几件事:
1、检查A的账户余额>500元;
2、A 账户中扣除500元;
3、B 账户中增加500元;- 正常的流程走下来,A账户扣了500,B账户加了500,皆大欢喜。
- 那如果A账户扣了钱之后,系统出故障了呢?A白白损失了500,而B也没有收到本该属于他的500。
- 以上的案例中,隐藏着一个前提条件:A扣钱和B加钱,要么同时成功,要么同时失败。事务的需求就在于此
-
2.2、所谓事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。
例如,银行转帐工作:从一个帐号扣款并使另一个帐号增款,这两个操作要么都执行,要么都不执行。所以,应该把他们看成一个事务。事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性 -
2.3、事务四大特性(简称ACID)
- 原子性 (Atomicity)
- 一致性 (Consistency)
- 隔离性 (Isolation)
- 持久性 (Durability)
以下内容出自《高性能MySQL》第三版,了解事务的ACID及四种隔离级有助于我们更好的理解事务运作。
下面举一个银行应用是解释事务必要性的一个经典例子。假如一个银行的数据库有两张表:支票表(checking)和储蓄表(savings)。现在要从用户Jane的支票账户转移200美元到她的储蓄账户,那么至少需要三个步骤:
- 检查支票账户的余额高于或者等于200美元。
- 从支票账户余额中减去200美元。
- 在储蓄帐户余额中增加200美元。
上述三个步骤的操作必须打包在一个事务中,任何一个步骤失败,则必须回滚所有的步骤。
可以用START TRANSACTION语句开始一个事务,然后要么使用COMMIT提交将修改的数据持久保存,要么使用ROLLBACK撤销所有的修改。事务SQL的样本如下:1、start transaction; 2、select balance from checking where customer_id = 10233276; 3、update checking set balance = balance - 200.00 where customer_id = 10233276; 4、update savings set balance = balance + 200.00 where customer_id = 10233276; 5、commit;
-
2.4、一个很好的事务处理系统,必须具备这些标准特性:
-
(1)、原子性(atomicity):保证了要么成功要么不成功
一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性
-
(2)、一致性(consistency):保证了在commit之前,不会因为系统挂了而出现错误
数据库总是从一个一致性的状态转换到另一个一致性的状态。(在前面的例子中,一致性确保了,即使在执行第三、四条语句之间时系统崩溃,支票账户中也不会损失200美元,因为事务最终没有提交,所以事务中所做的修改也不会保存到数据库中。)
-
(3)、隔离性(isolation):一个sql的执行不会影响另外一个sql的执行,也就是一个sql执行完,才会执行另外一个sql语句
通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。(在前面的例子中,当执行完第三条语句、第四条语句还未开始时,此时有另外的一个账户汇总程序开始运行,则其看到支票帐户的余额并没有被减去200美元。)
-
(4)、持久性(durability): 永久性存储
一旦事务提交,则其所做的修改会永久保存到数据库。(此时即使系统崩溃,修改的数据也不会丢失。)
-
-
2.5、事务命令
表的引擎类型必须是innodb类型才可以使用事务,这是mysql表的默认引擎-
(1)、查看表的创建语句,可以看到engine=innodb
查看表的创建语句,可以看到engine=innodb-- 选择数据库 use jing_dong; -- 查看goods表 show create table goods;
-
(2)、开启事务,命令如下:
开启事务后执行修改命令,变更会维护到本地缓存中,而不维护到物理表中begin; 或者 start transaction;
-
(3)、提交事务,命令如下
将缓存中的数据变更维护到物理表中commit;
-
(4)、回滚事务,命令如下:
回滚事务,命令如下:rollback;
-
-
2.6、注意
- (1)、修改数据的命令会自动的触发事务,包括insert、update、delete
- (2)、而在SQL语句中有手动开启事务的原因是:可以进行多次数据的修改,如果成功一起成功,否则一起会滚到之前的数据
-
2.7、提交
为了演示效果,需要打开两个终端窗口,使用同一个数据库(jing_dong),操作同一张表-
(1)、打开两个终端 1 与 2,都进行查询商品,内容是一模一样的
select * from good_cates;
-
(2)、增加数据
终端1:开启事务,插入数据begin; insert into good_cates(name) values('小米笔记本');
终端1:查询数据,此时有新增的数据
select * from good_cates;
-
(3)、查询
终端2:查询数据,发现并没有新增的数据(因为终端1修改的数据还没有进行提交)select * from good_cates;
-
(4)、提交
终端1:完成提交commit;
-
(5)、查询
终端2:查询,发现有新增的数据select * from goods_cates;
提示:当终端1在开启事务后,终端2修改表中的数据要等着终端1修改完再修改
-
-
2.8、回滚
为了演示效果,需要打开两个终端窗口,使用同一个数据库jing_dong
,操作同一张表-
step1:连接
终端1select * from good_cates;
-
step2:增加数据
终端2:开启事务,插入数据begin; insert into good_cates(name) values('游戏机');
终端2:查询数据,此时有新增的数据
select * from good_cates;
-
step3:查询
终端1:查询数据,发现并没有新增的数据select * from good_cates;
-
step4:回滚
终端2:完成回滚rollback;
-
step5:查询
终端1:查询数据,发现没有新增的数据select * from good_cates;
-
三、索引
-
3.1、思考:在图书馆中是如何找到一本书的?
答:一般的应用系统对比数据库的读写比例在10:1左右(即有10次查询操作时有1次写的操作),而且插入操作和更新操作很少出现性能问题,遇到最多、最容易出问题还是一些复杂的查询操作,所以查询语句的优化显然是重中之重 -
3.2、解决办法
当数据库中数据量很大时,查找数据会变得很慢
优化方案:索引 -
3.3、索引是什么
索引 是 一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度 -
3.4、索引目的
索引的目的在于提高查询效率,可以类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql。如果没有索引,那么你可能需要把所有单词看一遍才能找到你想要的,如果我想找到m开头的单词呢?或者ze开头的单词呢?是不是觉得如果没有索引,这个事情根本无法完成? -
3.5、索引原理
- 除了词典,生活中随处可见索引的例子,如火车站的车次表、图书的目录等。它们的原理都是一样的,通过不断的缩小想要获得数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是我们总是通过同一种查找方式来锁定数据。
-
数据库也是一样,但显然要复杂许多,因为不仅面临着等值查询,还有范围查询(>、<、between、in)、模糊查询(like)、并集查询(or)等等。数据库应该选择怎么样的方式来应对所有的问题呢?我们回想字典的例子,能不能把数据分成段,然后分段查询呢?最简单的如果1000条数据,1到100分成第一段,101到200分成第二段,201到300分成第三段……这样查第250条数据,只要找第三段就可以了,一下子去除了90%的无效数据。
索引原理
-
3.6、 索引的使用 (数据很大,且经常用,我们就建立索引)
-
查看索引
show index from 表名;
-
创建索引
(1)、如果指定字段是字符串,需要指定长度,建议长度与定义字段时的长度一致
(2)、字段类型如果不是字符串,可以不填写长度部分create index 索引名称 on 表名(字段名称(长度))
-
删除索引:
drop index 索引名称 on 表名;
-
-
3.7、索引 demo 测试
-
(1)、创建测试表testindex
create table test_index(title varchar(10));
-
(2)、使用python程序(ipython也可以)通过pymsql模块 向表中加入十万条数据
from pymysql import connect def main(): # 创建Connection连接 conn = connect(host='localhost',port=3306,database='jing_dong',user='root',password='mysql',charset='utf8') # 获得Cursor对象 cursor = conn.cursor() # 插入10万次数据 for i in range(100000): cursor.execute("insert into test_index values('ha-%d')" % i) # 提交数据 conn.commit() if __name__ == "__main__": main()
-
(3)、查询
-
开启运行时间监测:
set profiling=1;
-
查找第1万条数据ha-99999
select * from test_index where title='ha-99999';
-
查看执行的时间:
show profiles;
-
为表title_index的title列创建索引:
create index title_index on test_index(title(10));
-
执行查询语句:
select * from test_index where title='ha-99999';
-
再次查看执行的时间
索引创建到查询时间的对比show profiles;
我们可以看到在创建索引后,查询的时间明显缩短了
-
-
-
3.8、注意:
- 要注意的是,建立太多的索引将会影响更新和插入的速度,因为它需要同样更新每个索引文件。对于一个经常需要更新和插入的表格,就没有必要为一个很少使用的where字句单独建立索引了,对于比较小的表,排序的开销不会很大,也没有必要建立另外的索引。
- 建立索引会占用磁盘空间
四、账户管理, 在 第一节课中的7.3已经展示过基本的账户管理
-
4.1、基本的了解
- 在生产环境下操作数据库时,绝对不可以使用root账户连接,而是创建特定的账户,授予这个账户特定的操作权限,然后连接进行操作,主要的操作就是数据的crud
- MySQL账户体系:根据账户所具有的权限的不同,MySQL的账户可以分为以下几种
- 服务实例级账号:,启动了一个mysqld,即为一个数据库实例;如果某用户如root,拥有服务实例级分配的权限,那么该账号就可以删除所有的数据库、连同这些库中的表
- 数据库级别账号:对特定数据库执行增删改查的所有操作
- 数据表级别账号:对特定表执行增删改查等所有操作
- 字段级别的权限:对某些表的特定字段进行操作
- 存储程序级别的账号:对存储程序进行增删改查的操作
- 账户的操作主要包括 创建账户、删除账户、修改密码、授权权限 等
-
4.2、授予权限
需要使用实例级账户登录后操作,以root为例,主要操作包括:查看所有用户、修改密码、删除用户,具体的每一个下面会介绍-
<1>、查看所有用户
-
所有用户及权限信息存储在mysql数据库的user表中
-
查看user表的结构: user 表在 mysql 数据库里面
// 展示所有的数据库 show databases; // 使用 mysql 库 use mysql; // 展示所有的表 show tables; // 查看 user 表 desc user;
-
主要字段说明:
- Host表示允许访问的主机
- User表示用户名
- authentication_string表示密码,为加密后的值
-
查看所有用户
查看所有用户select user,authentication_string,host from user;
-
-
<2>、创建账户、授权
-
需要使用实例级账户登录后操作,以root为例,也就是创建账户要用 root用户登录
-
常用权限 主要包括:
create、alter、drop、insert、update、delete、select
-
如果分配所有权限,可以使用
all privileges
-
(1)、创建账户 & 授权
mysql> grant 权限列表 on 数据库 to '用户名'@'访问主机' identified by '密码';
提示:权限列表如果是多个可以写:
create,alter,drop
,用逗号隔开;访问主机:指的是主机的IP,可以用 本地:localhost
,也可以%
表示任何电脑可登陆
例如:创建一个test5
的用户,给他jing_dong
库中所有表的select
的权限,并且可以在任何电脑登录:%
,密码给他设置为123456
-
step1: 用root用户登录
mysql -u root -p 输入密码进入 或者 mysql -u root -p密码
-
step2: 真正的创建用户并授予查询(
select
)权限mysql> grant select on jing_dong.* to test5@'%' identified by '123456';
提示:
- 可以操作python数据库jing_dong里面所有表,方式为:
jing_dong.*
- 访问主机通常使用
百分号%
表示此账户可以使用 任何ip
的主机 登录访问此数据库 - 访问主机可以设置成
localhost
或具体的ip
,表示只允许本机或特定主机访问 - 查看用户有哪些权限
show grants for test5@'%';
,如果不是%就该为其他的如:'localhost'
或者具体的ip:'ip'
- 可以操作python数据库jing_dong里面所有表,方式为:
-
step3: 退出root的登录
输入exit或quit或\q,按下回车退出, 或者control+D退出
-
step4: 使用test5账户登录,密码:123456
使用test5账户登录,密码:123456mysql -u test5 -p123456
那么 test5 对数据库后面的操作就不再说了,可查,其他的权限没有
-
-
-
-
4.3、账户操作
提示:下面的操作要使用 root 用户登录
-
<1>、修改权限:有关下面代码参数的含义可参考上面,其实也就是多了
with grant option;
grant 权限名称 on 数据库名 to 账户@主机 with grant option;
例如:给 test5 用户增加一个
update
权限grant select,update on jing_dong.* to test5@'%' with grant option;
-
更新修改后的权限
flush privileges;
-
-
<2>、上面给用户增加了
update
的权限,也就是可以更新jing_dong
库中所有表的权限了-
登录上 test5 的账号,打开goods表
登录上 test5 的账号,打开goods表// 登录 test5 账号 mysql -u test5 -p123456 // 使用 jing_dong 库 use jing_dong; // 查询 goods 表的信息 select * from goods;
-
修改
r510vc 15.6英寸游戏本
为华为 10.1英寸笔记本
修改 `r510vc 15.6英寸游戏本` 为 `华为 10.1英寸笔记本`update goods set name='华为 10.1英寸笔记本' where id=1;
-
-
<3>、修改账户密码
使用root登录,修改mysql数据库的user表-
使用
password()
函数进行密码加密update user set authentication_string=password('新密码') where user='用户名';
例如:
update user set authentication_string=password('456123') where user='test5';
-
注意修改完成后需要刷新权限
flush privileges
-
-
<4>、 删除账户
-
语法1:使用root登录
drop user '用户名'@'主机';
例:
drop user 'test5'@'%';
-
语法2:使用root登录,删除mysql数据库的user表中数据
delete from user where user='用户名';
例:
delete from user where user='laowang';
操作结束之后需要刷新权限
flush privileges
提示:推荐使用语法1删除用户, 如果使用语法1删除失败,采用语法2方式
-
-
<5>、 忘记 root 账户密码怎么办
- root 账户一般归老大管,我们不需要操作,除非你是老大😋
- 加入忘记了,到时候再来查
-
五、MySQL主从同步配置
-
5.1、主从同步的定义
- 主从同步使得数据可以从一个数据库服务器复制到其他服务器上,在复制数据时,一个服务器充当主服务器(master),其余的服务器充当从服务器(slave)。因为复制是异步进行的,所以从服务器不需要一直连接着主服务器,从服务器甚至可以通过拨号断断续续地连接主服务器。通过配置文件,可以指定复制所有的数据库,某个数据库,甚至是某个数据库上的某个表。
-
使用主从同步的好处:
- 通过增加从服务器来提高数据库的性能,在主服务器上执行写入和更新,在从服务器上向外提供读功能,可以动态地调整从服务器的数量,从而调整整个数据库的性能。
- 提高数据安全,因为数据已复制到从服务器,从服务器可以终止复制进程,所以,可以在从服务器上备份而不破坏主服务器相应数据
- 在主服务器上生成实时数据,而在从服务器上分析这些数据,从而提高主服务器的性能
-
5.2、主从同步的机制
主从同步的机制
- Mysql服务器之间的主从同步是基于二进制日志机制,主服务器使用二进制日志来记录数据库的变动情况,从服务器通过读取和执行该日志文件来保持和主服务器的数据一致。
- 在使用二进制日志时,主服务器的所有操作都会被记录下来,然后从服务器会接收到该日志的一个副本。从服务器可以指定执行该日志中的哪一类事件(譬如只插入数据或者只更新数据),默认会执行日志中的所有语句。
- 每一个从服务器会记录关于二进制日志的信息:文件名和已经处理过的语句,这样意味着不同的从服务器可以分别执行同一个二进制日志的不同部分,并且从服务器可以随时连接或者中断和服务器的连接。
- 主服务器和每一个从服务器都必须配置一个唯一的ID号(在my.cnf文件的[mysqld]模块下有一个server-id配置项),另外,每一个从服务器还需要通过CHANGE MASTER TO语句来配置它要连接的主服务器的ip地址,日志文件名称和该日志里面的位置(这些信息存储在主服务器的数据库里)
-
5.3、配置主从同步的基本步骤
- <1>、在主服务器上,必须开启二进制日志机制和配置一个独立的ID
- <2>、在每一个从服务器上,配置一个唯一的ID,创建一个用来专门复制主服务器数据的账号
- <3>、在开始复制进程前,在主服务器上记录二进制文件的位置信息
- <4>、如果在开始复制之前,数据库中已经有数据,就必须先创建一个数据快照(可以使用mysqldump导出数据库,或者直接复制数据文件)
- <5>、配置从服务器要连接的主服务器的IP地址和登陆授权,二进制日志文件名和位置
-
5.4、详细配置主从同步的方法
-
5.4.1、备份主服务器原有数据到从服务器,如果在设置主从同步前,主服务器上已有大量数据,可以使用mysqldump进行数据备份并还原到从服务器以实现数据的复制。
-
<1>、在阿里云主服务器上进行备份,执行命令:
mysqldump -u 用户名 -p密码 数据库名 --lock-all-tables > ~/master_db.sql
说明
-
-u
:用户名 -
-p
:示密码 -
--all-databases
:导出所有数据库,如果要指定某个库可以直接改为 库名就好 -
--lock-all-tables
:执行操作时锁住所有表,防止操作时有数据修改 -
~/master_db.sql
:导出的备份数据(sql文件)位置,可自己指定
-
例如:把数据
jing_dong
在另外一台服务器进行备份(也就是设置一个从服务器)
把数据 `jing_dong` 在另外一台服务器进行备份(也就是设置一个从服务器)mysqldump -uroot -p456123love jing_dong --lock-all-tables > ~/master_jing_dong_db.sql
-
<2>、在在另外一台阿里云服务器(从服务器)上进行数据还原
先把在 主服务器 上备份的数据导入到 从服务器使用root账号登录上从服务器后
ssh -p 22 root@IP
远程服务主服务器备份的文件:
master_jing_dong_db.sql
,复制过去的文件名字叫:slave_jing_dong_db.sql
,下面的ironman.ren
是我的ip对应的域名scp -P 22 root@ironman.ren:master_jing_dong_db.sql slave_jing_dong_db.sql
创建jing_dong
数据库create database jing_dong charset=utf8;
把刚才在处服务器备份出来的数据还原到 从服务器的数据库
jing_dong
里面
语法:mysql –u root –p密码 数据库名 < 备份的sql文件
,如下
查看是否复制后的状态mysql –u root –p123456 jing_dong < slave_jing_dong_db.sql
-
-
5.4.2、配置主服务器master
-
(1)、编辑设置mysqld的配置文件,设置
log_bin
和server-id
编辑设置mysqld的配置文件,设置`log_bin`和`server-id`vim /etc/my.cnf
-
(2)、重启mysql服务
sudo service mysql restart
-
(3)、登入主服务器中的mysql,创建用于从服务器同步数据使用的帐号
// 登录 mysql 的 root 用户 mysql –uroot –p密码 // 创建用于从服务器同步数据使用的帐号,权限是数据库的所有权限 GRANT REPLICATION SLAVE on *.* to slave@'%' identified by '123456'; // 刷新权限 FLUSH PRIVILEGES;
-
(4)、获取主服务器的二进制日志信息(查看创建后的状态) ,待会在从服务器要用到
查看创建后的状态show master status;
-
-
5.4.3、配置从服务器slave(我这里是在Linux下测试的)
-
(1)、编辑设置mysqld的配置文件,设置
log_bin
和server-id
编辑设置mysqld的配置文件,设置`log_bin`和`server-id`sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
-
(2)、重启mysql服务
sudo service mysql restart
-
(3)、登入主服务器中的mysql创建用于从服务器同步数据使用的帐号
change master to master_host='ironman.ren', master_user='slave', master_password='123456',master_log_file='mysql-bin.000001', master_log_pos=120;
提示:各个参数的解释
- master_host :
ironman.ren
是 主服务器的域名,你也可以使用IP - master_user :
slave
: 在主服务器创建的用于从服务器登录主服务器mysql的账号,在上面5.4.3中的(3)
创建的 - master_password :123456: 密码,在上面
5.4.3中的(3)
创建的 - master_log_file :mysql-bin.000001 上面5.4.3中的(3)创建账号的时候生成的,看
5.4.3中的(4)
查看的结果 ,也就是:前面查询到的主服务器日志文件名 - master_log_pos:120: 上面5.4.3中的(3)创建账号的时候生成的,看
5.4.3中的(4)
查看的结果 ,也就是:前面查询到的主服务器日志文件位置
- master_host :
-
-
5.4.4、测试主从同步
修改goods表里面最后一条数据的name
在做完上面的配置后,主从同步已经设置好了,那么下面我们进行测试,在主服务器的jing_dong
里面的goods表修改最后一条数据,把 商务双肩背包3 改为 商务包
提示:在主服务器修改
update goods set name='商务包' where id=21;
在从服务器看一下是否同步了,在下面的结果可以看到主从同步成功了😆
在从服务器看一下是否同步了// 登录从服务器的 mysql mysql –uroot –p密码 // 使用 jing_dong 表 use jing_dong; // 查询 goods 表最后一条数据 select * from goods;
-
参考博客一:linux开启MySQL binlog日志