视图 触发器 内置函数 流程控制 事务 存储过程

视图

什么是视图

"""
视图就是通过查询得到一张虚拟表,然后保存下来,下次可以直接使用
"""

为什么要用视图

"""
如果要平凡的操作一张虚拟表(拼表组成的),你就可以制作成视图,后续直接操作
其实视图也是表
"""

如何操作

# 固定语法
create view 表名 as 虚拟表的查询sql语句

# 具体操作
create view teacher2course as
select * from teacher INNER JOIN course on teacher.tid = course.teacher_id;

注意

"""
1、创建视图在硬盘上只会有表结构,没有表数据(数据还是来自于之前的表)
2、视图一般只用来查询,里面的数据不要继续修改,可能会影响真正的表
"""

视图到底使用频率高不高?

'''
不高
当你创建了很多视图之后,会造成表的不好维护
'''

# 总结
    视图了解即可,基本不用!!!

触发器

"""
在满足对表数据进行增、删、改的情况下,自动触发的功能

使用触发器可以帮助我们实现监控、日志...

触发器可以在六中情况下自动触发 增前 增后 删前删后 改前改后
"""

基本语法结构

create trigger 触发器的名字 before/after insert/update/delete on 表名
for each row
begin
    sql语句
end

# 具体使用 针对触发器的名字 我们通常需要做到见名知意
# 针对增前
create trigger tri_before_insert_t1 before insert on t1
for each row
begin
    sql语句
end
# 增后
create trigger tri_after_insert_t1 after insert on t1
for each row
begin
    sql语句
end
'''
针对删除和修改 书写格式一致
'''

ps:修改mysql默认的语句结束符  只作用于当前窗口
    delimiter $$  将默认的结束符号由;改为$$
    delimiter ; 改回来
    
# 案例
create table cmd(
    id int primary key auto_increment,
    USER CHAR(12),
    priv CHAR(12),
    cmd CHAR(12),
    sub_time datetime,# 提交时间
    success enum('yes','no') # 0代表执行失败
);

create table errlog(
    id int primary key auto_increment,
    err_cmd CHAR(64),
    err_time datetime
);
'''
当cmd表中的记录success字段是no那么就触发触发器的执行去errlog表中插入数据
NEW指代的就是一条条数据对象
'''
delimiter $$
create trigger tri_after_insert_cmd after insert on cmd 
for each row
begin
    if NEW.success = 'no' then
        insert into errlog(err_cmd,err_time) 
values(NEW.cmd,NEW.sub_time);
    end if;
end $$
delimiter ;

# 插入数据
insert into cmd(
    USER,
    priv,
    cmd,
    sub_time,
    success
)
values
    ('jason','0755','tasklist',NOW(),'yes'),
    ('jason','0755','cd',NOW(),'no'),
    ('jason','0755','dir',NOW(),'no'),
    ('jason','0755','tree',NOW(),'yes');
    
# 删除触发器
drop trigger tri_after_insert_cmd;

内置函数

跟存储过程是有区别的,存储过程是自定义函数,函数就类似于是内置函数

('jason','0755','tasklist',NOW(),'yes')  # NOW()获取当前时间

create table blog(
    id int primary key auto_increment,
    name char(32),
    sub_time datetime
);

insert into blog(name,sub_time)
values
    ('第1篇','2015-03-01 11:31:21'),
    ('第2篇','2015-03-11 16:31:21'),
    ('第3篇','2016-07-01 10:31:21'),
    ('第4篇','2016-07-22 09:23:21'),
    ('第5篇','2016-07-23 10:11:11'),
    ('第6篇','2016-07-25 11:21:31'),
    ('第7篇','2017-03-01 15:33:21'),
    ('第8篇','2017-03-01 17:32:21'),
    ('第9篇','2017-03-01 18:31:21');
    
select date_format(sub_time,'%Y-%m'),count(id) from blog group by date_format(sub_time,'%Y-%m');
 

流程控制

# if判断
delimiter //
CREATE PROCEDURE proc_if ()
BEGIN
    declare i int default 0;
    if i = 1 THEN
        SELECT 1;
    ELSEIF i = 2 THEN
        SELECT 2;
    ELSE
        SELECT 7;
    END IF;
END //
delimiter ;


# while循环

delimiter //
CREATE PROCEDURE proc_while ()
BEGIN
    DECLARE num INT ;
    SET num = 0 ;
    WHILE num < 10 DO
        SELECT
            num ;
        SET num = num + 1 ;
    END WHILE ;
delimiter ;

事务

什么是事务

"""
事务(Transaction),顾名思义就是要做的或所做的事情,数据库事务指的则是作为单个逻辑工作单元执行的一系列操作(SQL语句)。这些操作要么全部执行,要么全部不执行。

开启一个事务可以包含多条sql语句 这些sql语句要么同时成功
要么一个都别想成功 称之为事务的原子性

事务管理是每个数据库(oracle、mysql、db等)都必须实现的。
"""

为什么需要事务

"""
1、为数据库操作提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。

2、当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。
"""

事务的作用

"""
保证了对数据操作的安全性
"""

eg:还钱的例子
    egon用银行卡给我的支付宝转账 
        1、将egon银行卡账户的数据减1000块
        2、将jason支付宝账户的数据加1000块

        你在操作多条数据的时候,可能会出现几条操作不成功的情况

事务的四大特征

"""
ACID

A:原子性
  一个事务是一个不可分割的单位,事务中包含诸多操作
  要么同时成功,要么同时失败

C:一致性
  事务必须是使数据库从一个一致性的状态变到另外一个一致性的状态
  一致性跟原子性是密切相关的

I:隔离性
  一个事务的执行不能被其他事务干扰
  (即一个事务内部的操作及使用到的数据对并发的其他事务是隔离的,并发执行的事务之间也是相互不干扰的)

D:持久性
  也叫'永久性'
  一个事务一旦提交成功执行成功,那么它对数据库的数据的操作也是永久的
  接下来的其他操作或者故障不应该对其有任何的影响
"""

举例

"""
A:原子性
    A给B转了100,A余额减100,刚转完系统崩溃了,B收到钱款的这一操作并没有执行,则整个事务回滚,100元退还到A的余额。

C:一致性
    例如转账行为中,一个人减了100元,另外一个人就应该加上这100元,而不能是50元,二者钱数相加始终不变。
    字段约束不能为负数,事务执行完毕之后的该字段也同样不能是负数。

I:隔离性
    A给B转100元,和C给B转100元是独立的。

D:持久性
    成功执行的事务产生的结果应该被永久的保留在数据库中。
"""

如何使用事务

# 事务相关的关键字
# 1、开启事务
# 方式一
start transaction;        
# 方式二
begin;
# 2、回滚操作(回到事务执行之前的状态)
rollback
# 3、确认(确认之后就无法回顾了)
commit;

'''模拟转账功能'''
create table user(
  id int primary key auto_increment,
  name char(16),
  balance int
);

insert into user(name,balance) values
('jason',1000),
('egon',1000),
('tank',1000);

# 1、先开启事务
start transaction;
# 2、多条sql语句
update user set balance=900 where name='jason';
update user set balance=1010 where name='egon';
update user set balance=1090 where name='tank';

'''
总结:
    当你想让多条sql语句保持一致性,要么同时成功,要么同时失败
    你就应该考虑使用事务
'''

事务开启的三种方式

"""
方式一:
显式开启
begin;
start transaction;
显式结束
commit;  # 提交
rollback;  # 回滚

方式二:
隐式开启/隐式结束
默认是这种模式

方式三:
隐式开启/显式结束
设置SET IMPLICIT_TRANSACTIONS ON;
"""

事务设置保存点

"""
事务可以设置保存点,保存点savepoint和快照类似,当事务结束时保存点会被删除,在事务结束之前可以回退到任意保存点
"""
# 设置保存点
savepoint 保存点的名字;
# 回滚到保存点 该保存点之后的操作无效
rollback to savepoint 保存点的名字;
# 回滚整个事务,删除所有保存点

存储过程

"""
存储过程就类似于python中的自定义函数

它的内部包含了一系列可以执行的sql语句,存储过程存放于MySQL服务端中,你可以直接通过调用存储过程触发内部sql语句的执行
"""

基本使用

create proceddure 存储过程的名字(形参1,形参2,...)
begin
    sql代码
end
# 调用
call 存储过程的名字()

三种开发模式

第一种

"""
应用程序:程序员写代码开发
MySQL:提前编写好存储过程,供程序员调用

好处:开发效率提升了 执行效率也上去了
缺点:考虑到人为元素,跨部门沟通的问题,后续的存储过程的扩展性差
"""

第二种

"""
应用程序:程序员写代码开发之外,设计到数据库操作也自己动手写

优点:扩展性高
缺点;开发效率降低
     编写sql语句太过繁琐,而且后续还要考虑sql优化的问题
"""

第三种

"""
应用程序:只写程序代码,不写sql语句,基于别人写好的操作MySQL的python框架直接调用操作即可
        ORM框架
优点:开发效率比上面两种情况都要高
缺点:语句的扩展性差,可能会出现效率低下的问题
"""

第一种基本不用,一般都是第三种,出现效率问题再手动写sql

存储过程具体演示

delimiter $$
create procedure p1(
    in m int,  # 只进不出 m不能返回
    in n int,
    out res int  # 该形参可以返回出去
)
begin
    select tname from teacher where tid>m and tid<n;
    set res=666;  # 将res变量修改,用来标识当前的存储过程代码确实执行了 
end $$
delimiter ;

# 针对形参res不能直接传数据,应该传一个变量名
# 定义变量
set @ret = 10
# 查看变量对应的值
select @ret;

在pymysql模块中如何调用存储过程呢?

import pymysql

conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user = 'root',
    password='123456',
    db='day48',
    charset='utf8',
    autocommit=True  # 设置自动提交
)
cursor = conn.cursor(pymysql.cursors.DictCursor)
# 调用存储过程
cursor.callproc('p1',(1,5,10))
'''
@_p1_0=1
@_p1_1=5
@_p1_2=10
'''
# print(cursor.fetchall())
cursor.execute('select @_p1_2;')
print(cursor.fetchall())  # [{'@_p1_2': 0}]

 

posted @ 2021-06-10 17:03  Palpitate~  阅读(40)  评论(0编辑  收藏  举报