十八、python学习之MySQL数据库(五):数据库其他高级操作

版权声明:浅弋、璃鱼的原创 https://blog.csdn.net/qq_35709559/article/details/82758392

一、视图:

1.什么是视图:

视图是一种基于查询结果产生的虚拟表。

当出现查询频率高并且查询语句非常复杂的情况时,每次都将复杂的SQL语句进行复写,非常不方便而且容易出错,因此视图的作用就体现出来了。

例如:查询每种商品的名字以及对应商品种类和品牌名(涉及了三表查询):

mysql> select goods.name "good_name", goods_cates.name "cate_name", goods_brands.name "brand_name" from goods inner join goods_cates on goods.catgoods_cates.id inner join goods_brands on goods.brand_id = goods_brands.id

 请大家随意的感受一下,这是一件多么恶心的事:

如此恶心的查询操作,但是查询到的结果还是蛮有用的,所以,用视图把查询过程保存下来。

2.视图的特性:

  • 视图时一种虚拟表,实际上是对一条封装起来的复杂的SQL查询语句。
  • 在使用视图时,就相当于先执行了这一条复杂的SQL语句,再对其返回的结果进行操作。
  • 视图不存储具体的数据。
  • 视图的基本表大声变化,那么视图也随之变化。

3.定义视图:

视图在定义时,建议使用v_xxx形式命名,以便和普通的表区分。

语法:create view 视图名称 as selec 语句

create view v_goods_info as select goods.name "good_name", goods_cates.name "cate_name", goods_brands.name "brand_name" from goods inner join goods_cates on goods.cate_id = goods_cates.id inner join goods_brands on goods.brand_id = goods_brands.id;

4.使用视图:

视图的作用就是用来查询的,视图以表的形式实现了对复杂SQL语句的封装。

/*查询笔记本类型的商品及其品牌*/
select * from v_goods_info where cate_name = "笔记本";

原来复杂的三表联查,现在通过视图加一条简单的查询语句就完成了。

5. 删除视图:

语法:drop view 视图名称;

drop view v_goods_info;

6.视图小结:

* 视图封装了对多张基本表的复杂操作,简化用户操作;
* 视图只是一个虚表,并不存储任何基本表的表数据,当用户使用视图的时候 视图会从基本表中取出;
* 通过视图可以对用户展示指定字段从而屏蔽其他字段数据,更加安全;

二、事务:

1.什么是事务:

事务(Transaction),是指作为基本工作单元执行一系列SQL语句的造作,要么完全的执行,要么都不执行。

2.为什么要有事务:

以下内容出自《高性能MySQL》第三版,了解事务的ACID有助于我们更好的理解事务运作。 下面举一个银行应用是解释事务必要性的一个经典例子。假如一个银行的数据库有两张表:支票表(checking)和储蓄表(savings)。现在要从用户Jane的支票账户转移200美元到她的储蓄账户,那么至少需要三个步骤:

> 1. 检查支票账户的余额高于或者等于200美元。
> 2. 从支票账户余额中减去200美元。
> 3. 在储蓄帐户余额中增加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;

3. 事务的四大特性(ACID):

  • 原子性(Atomicity):

一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么做完全部提交成功,要么全部失败回滚。对于一个事务来说,不可能只执行一部分操作,这就是事务的原子性。

  • 一致性(Consistency):

数据库总是从一个一致性的状态切换到另一个一致性的状态。

  • 隔离性(Isolation):

通常来说,一个事务所作的修改在最终提交之前对其他事务都是不可见的。

  • 持久性(Durability):

一旦事务提交,则其所作的操作会被永久的保存到数据库。

4.事务的操作:

Mysql使用InnoDB引擎支持事务操作。

4.1开启事务:

开启事务后执行修改命令,变更会维护到本地缓存中,而不是维护到物理库表中

begin;
--或:
start transaction;

4.2 提交事务:

将缓存中的数据变更维护到物理库表中

commit

4.3 回滚事务:

放弃缓存中变更的数据,表示事务执行失败,放弃事务阶段执行的变更操作、

rollback;

5. 代码简单实现存银行转账:

场景:假如一个银行的数据库有两张表:支票表(checking)和储蓄表(savings)。现在要从用户Jane的支票账户转移200美元到她的储蓄账户。

5.1 创建数据库:

/* 创建名为brank的数据库 */
create database brank charset = utf8;

5.2 创建数据表:

use brank;
create table checking(id int primary key auto_increment, account char(20), username varchar(20), money int);
create table savings(id int primary key auto_increment, account char(20), username varchar(20), money int);

创建两张数据表:支票表(checking)和储蓄表(savings),字段:id、account(账号)、user(用户名)、money(余额,额度X1000保存)

5.3 添加数据:

/*支票(checking)表中创建用户Jane,余额1000元*/
insert into checking(account, username, money) values("3323755267", "Jane", 1000000);
/*余额(savings)表中创建账户Jane,余额100元*/
insert into savings(account, username, money) values("3323755267", "Jane", 100000);

5.4 代码实现:

#!/usr/bin/venv python3
# coding: utf-8

"""
假如一个银行的数据库有两张表:支票表(checking)和储蓄表(savings)。
现在要从用户Jane的支票账户转移200美元到她的储蓄账户。
"""

from pymysql import *
import config    # 引入数据库配置参数


class SqlControl(object):
    def __init__(self):
        """初始化对象,创建数据库连接和游标"""
        self.__conn = Connect(host=host, port=port, database=database,
                              user=user, password=password, charset='utf8')
        self.__cur = self.__conn.cursor()

    def run(self):
        print("现在进行转账操作:支票(checking) --> 储蓄(savings)")
        # 查询支票余额:
        sql_fetch_checking = '''select money from checking where account = "3323755267";'''
        self.__cur.execute(sql_fetch_checking)
        checking_money = (float)(self.__cur.fetchone()[0])/1000
        print("当前支票账户:%.2f元" % checking_money)
        # 查看当前储蓄账户余额
        sql_fetch_saving = '''select money from savings where account = "3323755267";'''
        self.__cur.execute(sql_fetch_saving)
        saving_money = (float)(self.__cur.fetchone()[0]) / 1000
        print("当前储蓄账户:%.2f元" % saving_money)

        # 开始转账操作
        for _ in range(3):
            change = float(input("请输入支票->储蓄的转账金额(元):"))
            if change > checking_money:
                print("支票账户余额不足,当前余额为:%.2f" % checking_money)
            else:
                break

        # 执行事务操作
        self.__cur.execute("begin")
        # 支票余额减去转账金额
        sql_checking = '''update checking set money = (money - %s) where account = "3323755267";'''
        self.__cur.execute(sql_checking, (str(int(change*1000)),))
        sql_saving = '''update savings set money = (money + %s) where account = "3323755267";'''
        self.__cur.execute(sql_saving, (str(int(change*1000)),))

        # 查询支票余额:
        sql_fetch_checking = '''select money from checking where account = "3323755267";'''
        self.__cur.execute(sql_fetch_checking)
        checking_money = (float)(self.__cur.fetchone()[0]) / 1000
        print("当前支票账户:%.2f元" % checking_money)
        # 查看当前储蓄账户余额
        sql_fetch_saving = '''select money from savings where account = "3323755267";'''
        self.__cur.execute(sql_fetch_saving)
        saving_money = (float)(self.__cur.fetchone()[0]) / 1000
        print("当前储蓄账户:%.2f元" % saving_money)

        option = input("是否确认操作(y/n):")
        if option.lower() == "y":
            # 提交
            self.__cur.execute("commit;")
        elif option.lower() == "n":
            # 回滚
            self.__cur.execute("rollback;")

        print("操作完成...")

    def __del__(self):
        self.__cur.close()
        self.__conn.close()


if __name__ == '__main__':
    account = SqlControl()
    account.run()

说明:这段代码仅仅是以实现功能为目的,并没有对功能完成很好的封装。

三、索引:

1.什么是索引:

能够快速查询数据的线索就称之为索引。

索引的目的在于提高查询的效率。

2.Mysql索引的使用:

2.1 查看表中已有的索引:

show index from 表名;

2.2 创建索引:

create index 索引名 on 表名(字段名(长度));

如果指定字段是字段名,需要指定长度,建议长度与定义字段时的长度一致。

字段类型如果不是字符串,可以不填写长度部分。

2.3 删除索引:

drop index 索引名称 on 表明;

3.验证索引的效率:

3.1 准备数据:

create table test_index(title varchar(10));

3.2 准备10w条数据:

#!/usr/bin/venv python3
# coding: utf-8
from pymysql import *
import config


def main():
    # 创建连接
    conn = Connect(host = host, port = port, database = database, user = user, password = password, charset = "utf8" )
    cur = conn.cursor()
    # 插入10w条数据
    for i in range(100000):
        cur.execute("""insert into test_index values('haha-%s')""", (i,))

    # 提交数据
    conn.commit()


if __name__ == '__main__':
    main()

3.3 查看验证:

  • 开启运行时间监测

set profiling=1;

  • 查询 ha-99999 的数据

select * from test_index where title='ha-99999;

  • 为表 test_index 创建索引 

create index title_index on test_index(title(10));

  • 再次查询 ha-99999 的数据

select * from test_index where title='ha-99999;

  • 查看执行时间

show profiles;

  • 使用 desc 命令也可以查看索引的效率

desc select * from test_index where title='ha-99999';

4. 索引小结:

  1. 索引可以明显提高某些字段的查询效率。
  2. 但不是所有的表都需要建立索引 
  3. 如果表中数据很少,没有必要建立索引
  4. 如果一个表中的数据增删很频繁,不能建立索引 ,因为只要数据发生增减,索引就要重新建立。增加了系统开销,反而慢了。
  5. 索引只适合查询操作频繁的表。

四、用户管理:

之前在登陆数据时,一直使用的都是 root 用户, root用户是数据库系统中的超级管理员,可以对数据库做任何操作。在生产环境中,开发人员一般只是对数据做读取操作。root 用户对于普通人来说,权限太大了,如果不小心做了一些不可逆的操作。那么后果是非常严重的。所以 root 用户不会让开发人员使用,一般会由DBA或运维人员统一管理。给开发人员针对项目的数据库建立专门的用户来操作。

1.查看所有用户:

mysql中所有的用户及权限信息都保存在mysql数据库的user表中。

1.1 通过 desc user; 可以查看user表中的结构

主要的字段:

Host:允许访问的主机地址,localhost:为本机;%为任何主机。

User:用户名

authentication_string:密码,保存的是加密后的值

1.2 查看所有用户:

select host, user, authentication_string from user;

☆2.创建账户、授权:

△:用户管理操作的权限都是由管理员操作的,只能使用root用户操作。

  • 常用权限:create、alter、drop、update、delete、select
  • 全部权限:,all privilages

语法: grant 权限列表 on 数据库.数据表 to '用户名' @ '访问主机' identified by '密码'; 

例如:

-- 创建用户JDAdmin拥有查询的权限,且全网可登陆
grant select on JD.* to "JDAdmin"@"%" identified by "12345679";

3. 查看权限:

语法:show grants for 用户名@主机地址;

说明:

USAGE:表示对该数据库拥有使用权

SELECT:表示对该数据库拥有查询权

4.修改权限:

语法:grant 权限名称 on 数据库 to 账户@主机 with grant option;

           flush privileges;        -- 刷新权限

 

5. 删除用户:

语法:drop user 用户名@主机地址

drop user "JDAdmin"@"%";

6.小结:

用户管理是MySQL当中一块非常重要的内容,它涉及到了数据的安全问题。 但是对于开发人员来讲,这块内容在实际工作中涉及又不多,因为数据库的维护会有专门的运维人员或DBA来完成。 一般在操作数据时,不会使用root用户。DBA会针对不同项目需求给你专门创建用户,甚至是视图。

数据库高级部分的内容,大家主要做一个了解即可。当遇到问题时,要知道如何解决。或者可以快速找到解决办法。 对于数据库编程。对表的CURD才是重要的。


MySQL主从配置实在是不想搞,,,有点麻烦,,感兴趣的可以直接去百度,有很多大佬写了关于Mysql主从配置的文章。

猜你喜欢

转载自blog.csdn.net/qq_35709559/article/details/82758392