1.0 视图
1.1 视图介绍
视图是一种虚拟存在的表,它并不在数据库中实际存在,行和列来自查询视图自定义的表,使用视图时动态生成的。
1.2 定义视图
create view 视图名称 as select 语句
SELECT * FROM provinces;
CREATE VIEW v_pro AS SELECT * FROM provinces;
SELECT * FROM v_pro;
1.3 查看视图
show tables;
1.4 使用视图
select * from v_pro;
1.5 删除视图
drop view 视图名称
1.6 视图的作用
- 简单
- 提高了重用性,就像一个函数
- 安全
- 提高了安全性能,可以针对不同用户创建不同的视图
- 数据独立
- 一旦视图的结构确定了,可以屏蔽表结构变化对用户的影响,源表增加列对视图没有影响;源表修改列名,则可以通过修改视图来解决,不会造成对访问者的影响
1.7 视图的修改
有下列内容之一,视图不能做修改
• select子句中包含distinct
• select字句中包含组函数
• select语句中包含group by子句
• selecy语句红包含order by子句
• where子句中包含相关子查询
• from字句中包含多个表
• 如果视图中有计算列,则不能更新
• 如果基表中有某个具有非空约束的列未出现在视图定义中,则不能做insert操作。
2.0 事务
2.1 为什么要有事务
事务广泛用于订单系统、银行系统等多种场景,例如:
A用户和B用户是银行的储户,现在A要给B转账500元,那么需要做以下几件事:
- 检查A的账户余额>500元;
- A 账户中扣除500元;
- B 账户中增加500元;
正常的流程走下来,A账户扣了500,B账户加了500,皆大欢喜。
那如果A账户扣了钱之后,系统出故障了呢?A白白损失了500,而B也没有收到本该属于他的500。
以上的案例中,隐藏着一个前提条件:A扣钱和B加钱,要么同时成功,要么同时失败。事务的需求就在于此.
2.2 事务
所谓事务,它是一个操作序列,要么都执行,要么都不执行,它是一个不可分割的工作单位.
事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性.
2.3 事务的四大特性,简称(ACID)
- 原子性(A)
- 一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性
- 一致性©
- 数据库总是从一个一致性的状态转换到另一个一致性的状态。(在前面的例子中,一致性确保了,即使在执行第三、四条语句之间时系统崩溃,支票账户中也不会损失200美元,因为事务最终没有提交,所以事务中所做的修改也不会保存到数据库中。)
- 隔离性(I)
- 通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。(在前面的例子中,当执行完第三条语句、第四条语句还未开始时,此时有另外的一个账户汇总程序开始运行,则其看到支票帐户的余额并没有被减去200美元。
- 持久性(D)
- 一旦事务提交,则其所做的修改会永久保存到数据库。(此时即使系统崩溃,修改的数据也不会丢失。)
2.4 事务的状态
我们现在知道事务是一个抽象的概念,它其实对应着一个或多个数据库操作,设计数据库的大叔根据这些操作所执行的不同阶段把事务大致上划分成了这么几个状态
- 活动的 (active)
- 事务对应的数据库操作正在执行过程中时,我们就说该事务处在活动的状态.
- 部分提交的 (partially committed)
- 当事务中的最后一个操作执行完成,但由于操作都在内存中执行,所造成的影响并没有刷新到磁盘时,我们就说该事务处在部分提交的状态。
- 失败的 (failed)
- 当事务处在活动的或者部分提交的状态时,可能遇到了某些错误(数据库自身的错误、操作系统错误或者直接断电等)而无法继续执行,或者人为的停止当前事务的执行,我们就说该事务处在失败的状态。
- 中止的 (aborted)
- 如果事务执行了半截而变为失败的状态,当狗哥账户的钱被扣除,但是猫爷账户的钱没有增加时遇到了错误,从而当前事务处在了失败的状态,那么就需要把已经修改的狗哥账户余额调整为未转账之前的金额,换句话说,就是要撤销失败事务对当前数据库造成的影响。书面一点的话,我们把这个撤销的过程称之为回滚。当回滚操作执行完毕时,也就是数据库恢复到了执行事务之前的状态,我们就说该事务处在了中止的状态。
5.提交的 (committed) - 当一个处在部分提交的状态的事务将修改过的数据都同步到磁盘上之后,我们就可以说该事务处在了提交的状态。
随着事务对应的数据库操作执行到不同阶段,事务的状态也在不断变化,一个基本的状态转换图如下所示
2.5 事务命令
- 开启事务后执行修改命令,变更会维护到本地缓存中,而不维护到物理表中
begin; 或者 start transaction; (后者可以加修饰符) - 将缓存的数据添加到物理表中,提交事务
commit;
回滚事务,让事务回到初始状态,放弃缓存中变更的事务
rollback;
2.6 保存点
如果你开启了一个事务,并且已经敲了很多语句,忽然发现上一条语句有点问题,你只好使用ROLLBACK语句来让数据库状态恢复到事务执行之前的样子,然后一切从头再来,总有一种一夜回到解放前的感觉。所以设计数据库的大叔们提出了一个保存点(英文:savepoint)的概念,就是在事务对应的数据库语句中打几个点,我们在调用ROLLBACK语句时可以指定会滚到哪个点,而不是回到最初的原点。
SAVEPOINT 保存点名称; # 创建保存点
当我们想回滚到某个保存点时,可以使用下边这个语句(下边语句中的单词WORK和SAVEPOINT是可有可无的):
ROLLBACK [WORK] TO [SAVEPOINT] 保存点名称;
不过如果ROLLBACK语句后边不跟随保存点名称的话,会直接回滚到事务执行之前的状态。
如果我们想删除某个保存点,可以使用这个语句:
RELEASE SAVEPOINT 保存点名称;
注意
• 修改数据的命令会自动的触发事务,包括insert、update、delete
• 而在SQL语句中有手动开启事务的原因是:可以进行多次数据的修改,如果成功一起成功,否则一起会滚到之前的数据
3.0 事务阿隔离级别
3.1隔离级别(ISOLATION LEVEL)
隔离性其实比想象要复杂。在SQL中定义了四种隔离的级别,每一种隔离级别都规定了一个事务中的修改,哪些是在事务内和事务间是可见的,哪些是不可见的。较低级别的隔离通常来说能承受更高的并发,系统的开销也会更小。
3.2 查看当前的事务级别
SELECT @@tx_isolation;
3.3 设置mysql的隔离级别
set session transaction isolation level 设置事务隔离级别
1. READ UNCOMMITTED(未提交读)
在READ UNCOMMITTED级别,事务的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,这也被称为脏读(Dirty Read)。这个级别的隔离会导致很多问题,虽然在性能方面是最优的,但是缺乏其他级别的很多好处,所以这种隔离的级别很少在实际中应用。
2. READ COMMITTED(读已提交)
大多数数据库系统默认的隔离级别都是READ COMMITTED(但MySQL不是),"读已提交"简单的定义:一个事务只能看见已经提交的事务的修改结果。换句话说,一个事务从开启事务到提交事务之前,对其他事务都是不可见的,因此在同一个事务中的两次相同查询结果可能不一样。故这种隔离级别有时候也叫不可重复读(NONREPEATABLE READ)。
3. REPEATABLE READ(可重复读)
"可重复读"是MySQL的默认事务隔离级别。REPEATABLE READ解决了脏读的问题,该级别保证了在同一次事务中多次查询相同的语句结果是一致的。但是"可重复读"隔离级别无法避免产生幻行(Phantom Row)的问题,MySQL的InnoDB引擎通过多版本并发控制(MVCC,Multiversion Concurrency Controller)解决了幻读的问题。
4. SERIALIZABLE(可串行化)
SERIALIZABLE是最高的隔离级别,它通常通过强制事务串行,避免了前面说的幻读问题。简单来说,"可串行化"会在读取的每一行数据上都加锁,所以可能会导致大量的锁等待和超时问题,所以在实际的生产环境中也很少会用到这个隔离级别,只有在非常需要确保数据的一致性切可以接受没有并发的情况下,才会考虑使用这个隔离级别。
4.0 索引
当数据库中数据量很大时,查找数据会变得很慢.
优化方案:索引
4.1 索引是什么
索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。
更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度。
4.2 索引的目的
索引的目的在于提高查询效率,可以类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql。
4.3 索引的原理
- 除了词典,生活中随处可见索引的例子,如火车站的车次表、图书的目录等。它们的原理都是一样的,通过不断的缩小想要获得数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是我们总是通过同一种查找方式来锁定数据。
- 数据库也是一样,但显然要复杂许多,因为不仅面临着等值查询,还有范围查询(>、<、between、in)、模糊查询(like)、并集查询(or)等等。数据库应该选择怎么样的方式来应对所有的问题呢?
4.4 索引的使用
- (1)查看索引
show index from 表名;
- (2)创建索引
#如果指定字段是字符串,需要指定长度,建议长度与定义字段时的长度一致
#字段类型如果不是字符串,可以不填写长度部分
create index 索引名称 on 表名(字段名称(长度));
4.5 删除索引
drop index 索引 on 表名;
4.6 索引案例
创建测试表test
create table test(title varchar(10));
使用python程序向表中加入十万条数据
import pymysql
def main():
conn = pymysql.connect(host='127.0.0.1',port = 3306,user='root',passwd='root',db='demp82',charset='utf8')
cursor = conn.cursor()
for i in range(100000):
cursor.execute("insert into test values('jr-%d')" % i)
conn.commit()
if __name__ == '__main__':
main()
4.7 查询
- 开启运行时间监测
set profiling=1;
- 查找第1万条数据ha-99999
select * from test where title='ha-99999';
- 查看执行的时间
show profiles;
- 为表title_index的title列创建索引
create index title_index on test(title(10));
- 执行查询语句
select * from test where title='ha-99999';
- 再次查看执行的时间
show profiles;
适合建立索引的情况:
• 主键自动建立索引
• 频繁作为查询条件的字段应该建立索引
• 查询中与其他表关联的字段,外键关系建立索引
• 在高并发的情况下创建复合索引
• 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度 (建立索引的顺序跟排序的顺序保持一致)
不适合建立索引的情况:
• 频繁更新的字段不适合建立索引
• where条件里面用不到的字段不创建索引
• 表记录太少,当表中数据量超过三百万条数据,可以考虑建立索引
• 数据重复且平均的表字段,比如性别,国籍
5.0 账户管理
5.1 账户管理
• 在生产环境下操作数据库时,绝对不可以使用root账户连接,而是创建特定的账户,授予这个账户特定的操作权限,然后连接进行操作,主要的操作就是数据的crud
• MySQL账户体系:根据账户所具有的权限的不同,MySQL的账户可以分为以下几种
• 服务实例级账号:,启动了一个mysqld,即为一个数据库实例;如果某用户如root,拥有服务实例级分配的权限,那么该账号就可以删除所有的数据库、连同这些库中的表
• 数据库级别账号:对特定数据库执行增删改查的所有操作
• 数据表级别账号:对特定表执行增删改查等所有操作
• 字段级别的权限:对某些表的特定字段进行操作
• 存储程序级别的账号:对存储程序进行增删改查的操作
• 账户的操作主要包括创建账户、删除账户、修改密码、授权权限等
5.2 创建用户
命令:CREATE USER 'username'@'host' IDENTIFIED BY 'password';
说明:
• username:登录的用户名
• password:是登录的密码
• host:指定可以登录的主机,其中localhost表示本机,%表示所有主机
CREATE USER 'testuser'@'%' IDENTIFIED BY '123';
5.3 修改用户
MySQL修改用户的信息使用ALTER USER语句,比如我们要修改当前用户的密码,可以这样
mysql> ALTER USER USER() IDENTIFIED BY 'test123457';
5.4 删除用户
MySQL删除用户使用DROP USER语句,该语句用法如下
DROP USER [IF EXISTS] user [, user] ...
删除用户,要用root用户进行删除
drop USER juran;
5.5 授予权限
需要使用实例级账户登录后操作,以root为例
主要操作包括:
• 查看所有用户
• 修改密码
• 删除用户
所有用户及权限信息存储在mysql数据库的user表中
查看user表的结构
desc user;
• 主要字段说明:
• Host表示允许访问的主机
• User表示用户名
• authentication_string表示密码,为加密后的值
查看所有用户
select host,user,authentication_string from user;
创建账户、授权
- 需要使用实例级账户登录后操作,以root为例
- 常用权限主要包括:create、alter、drop、insert、update、delete、select
- 如果分配所有权限,可以使用all privileges
grant 权限列表 on 数据库 to '用户名'@'访问主机' identified by '密码';
注意:
使用GRANT进行授权时,如果该用户不存在,可以跟上GRANT语句后面跟上IDENTIFIED BY直接创建该用户,不过如果在创建用户时要设置更详细的信息,则应该使用CREATE USER语句来创建用户。
示例1:
创建一个laowang的账号,密码为123456,只能通过本地访问, 并且只能对jing_dong数据库中的所有表进行读操作
1:使用root登录
mysql -uroot -p
step2:创建账户并授予所有权限
grant select on jing_dong.* to 'laowang'@'localhost' identified by '123456';
**如果报错,先刷新下数据库权限**
mysql> grant select on jd.* to 'laowang'@'localhost' identified by '123456';
ERROR 1290 (HY000): The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement
mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)
mysql> grant select on jd.* to 'laowang'@'localhost' identified by '123456';
Query OK, 0 rows affected, 1 warning (0.00 sec)
说明
• 可以操作python数据库的所有表,方式为:jing_dong.*
• 访问主机通常使用 百分号% 表示此账户可以使用任何ip的主机登录访问此数据库
• 访问主机可以设置成 localhost或具体的ip,表示只允许本机或特定主机访问
• 查看用户有哪些权限
show grants for laowang@localhost;
接下来删除jd数据库中的goods表数据,进行测试
delete from goods where id = 21;
示例2:
创建一个laoli的账号,密码为12345678,可以任意电脑进行链接访问, 并且对jing_dong数据库中的所有表拥有所有权限
grant all privileges on jing_dong.* to "laoli"@"%" identified by "12345678"
6.0 权限列表
下面是使用GRANT语句可以授予的全部权限,不同的权限有不同的作用域,比如有的是全局权限,有的只作用于数据库等