数据库之进阶(视图,事务,存储过程)

1.视图
什么是视图:
通过查询得到的虚拟表,然后保存下来,下次用的时候直接用即可
为什么要用视图:
减少sql代码和重复查询
怎么用视图:
语法:create view 视图名 as 虚拟表(通过查询获得的虚拟表)

create view b2a as 
select b.book_jd,group_concat(author.name) "author_name" from
book_author as b left join author on b.author_id = author.id group
by b.book_id

注意:
1.在硬盘中,视图只有表结构文件,没有表数据文件
2.视图通常用于查询,尽量不要修改视图中的数据
(通常视图是多个表的拼接结果,不知道会改了哪个表)
开发时,通常不用视图,扩展性差,如果表修改了,还要修改视图

2.触发器
什么叫触发器:
在满足对某张表数据的增,删,改(查询不会触发)的情况下,自动触发的功能
称之为触发器#类似log模块的功能,log是我们在需要的地方人为设置
触发器是自动触发的

为什么要用触发器:
可以监测对表的修改动作,以便后续检查

怎么用触发器:
触发器语法:

①触发器的命名 tri_after(两种选择,after,before)_insert(三种选择,update,insert,delete)_t2(对哪张表进行的修改)
②创建语法:
create trigger tri_after_insert_t2   after insert  on t2 for each row;
delimiter // #将mysql默认的结束标志;改为//
begin
       if NEW.success = "no" then#将插入的每条记录当做对象NEW
        insert into errlog(err_cmd,err_time)values(NEW.cmd,NEW.sub_time);
        end if;
end //
delimiter ; #将结束标志改回来

例子:
CREATE TABLE cmd (
    id INT PRIMARY KEY auto_increment,
    USER CHAR (32),
    priv CHAR (10),
    cmd CHAR (64),
    sub_time datetime, #提交时间
    success enum ('yes', 'no') #0代表执行失败
);

CREATE TABLE errlog (
    id INT PRIMARY KEY auto_increment,
    err_cmd CHAR (64),
    err_time datetime
);

创建触发器:
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
    ('egon','0755','ls -l /etc',NOW(),'yes'),
    ('egon','0755','cat /etc/passwd',NOW(),'no'),
    ('egon','0755','useradd xxx',NOW(),'no'),
    ('egon','0755','ps aux',NOW(),'yes');
#now() mysql函数获取当前时间

#查询errlog,触发器执行成功
select * from errlog;
+----+-----------------+---------------------+
| id | err_cmd         | err_time            |
+----+-----------------+---------------------+
|  1 | cat /etc/passwd | 2019-01-13 13:51:47 |
|  2 | useradd xxx     | 2019-01-13 13:51:47 |
+----+-----------------+---------------------+

注意:1.创建前将默认结束标志修改 delimiter //
         2.创建触发器时,不用加;结束
        3.流程控制的if语句 判断条件一个= ,不以;作为判断结束,而是以then
          4.触发器执行的sql语句必须以;结束            
        5.创建完成后,将结束标志改回;  delimiter ;

事务:
什么是事务:
开启一个事务可以包含一系列sql语句,这些sql语句要么同时成功,要么一个都别想成功,称之为事务的原子性(原子不可再分)
事务的作用:
transaction 英文也叫交易,主要用途保证交易的安全性
转账的时候,本质就是一方减钱另一方加钱,事务可以保证这两个行为要么同时成功,
要么都失败,避免了一方减钱,另一方没有加钱的情况发生
如何用事务:
语法:
start transaction;#开启事务
rollback; #未有commit之前都可以清除修改
commit; #提交后才会将修改写入硬盘

用例:
create  table  user (
id  int primary key auto_increment,
name char(16),
salary float);

insert into user(name,salary) values("zb",1000),("egon",1000);

错误示范:
update user set  salary = 900 where name="zb";
update user set  salarys= 1010 where name = "egon";
#以上第一条语句执行成功,第2条由于字段名错误未有执行成功


start transaction;
update user set  salary = 900 where name="zb";
update user set  salarys= 1010 where name = "egon";
第二条报错
使用rollback;回滚,将修改动作取消
mysql> select * from user;
+----+------+--------+
| id | name | salary |
+----+------+--------+
|  1 | zb   |    900 |
|  2 | egon |   1000 |
+----+------+--------+
2 rows in set (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+----+------+--------+
| id | name | salary |
+----+------+--------+
|  1 | zb   |   1000 |
|  2 | egon |   1000 |

开启事务后对表进行修改,需要使用commit才会将修改写入硬盘,
提交后使用回滚rollback将无法回到未修改前状态

#事务缺少检测异常机制

存储过程

什么是存储过程:
存储过程包含了一系列可执行的sql语句,存储过程存放于mysql中(在mysql中实现的),通过调用它的名字可以执行其内部的一堆sql
相当于提供的接口

三种开发模式:
1.应用程序:只需要开发应用程序的逻辑,mysql编写好存储过程,以供程序调用
优点:开发效率,执行效率都高
缺点:人为因素,跨部门沟通等问题,会导致扩展性差

2.应用程序:除了开发应用程序的逻辑,还需要编写原生的sql
优点:比方式1扩展性高(非技术性)
缺点:开发效率,执行效率都不如方式1,编写原生sql太过于复杂,而且需要考虑sql语句的优化问题(应该主要是查询问题,索引相关)


3.应用程序:开发应用程序的逻辑,不需要编写原生sql,基于别人写好的框架来处理数据,orm
优点:不用再编写原生sql,开发效率比方式2高,同时兼容方式2扩展性高的好处
缺点:执行效率连方式2都不如
创建表:
create table teacher(
id int primary key auto_increment,
name char(16),
sex enum("male","female") default "male");

insert into teacher(name,sex) values("egon","male"),("alex","male"),("zero","male"),("owen","female");

#存储过程语法:
delimiter //
create procedure p1(
in m int,
in n int,
out res int )
#inout 即可以当输出又可以当输入)#创建存储过程跟事务一样不用加分号

begin
select name from teacher where id >m and id< n;
set res = 0;
end //
delimiter ;
#in 输入变量,不可当做输出变量
#out 输出数据
#inout 可输入可输出变量

使用
①在mysql中调用
set @res =10;
call p1(2,4,@res);#out的参数必须是变量,执行存储过程中的代码
select  @res;
②在python中使用
import pymysql as psql
#1.创建连接
c = psql.connect(
host = "localhost",
port = 3306,
db = "db12",
user="root",
passwd = "123")
#2.建立游标
cursor = c.cursor(psql.cursors.DictCursor)
#3.调用存储过程
cursor.callproc("p1",(2,4,10))#@_p1_0=2,@_p1_1=4,@_p1_2=10
print(cursor.fetchall())#获取结果
#select @_p1_2;mysql 语句
cursor.execute("select @_p1_2;")#返回结果是影响的行数
print(cursor.fetchone())#拿到返回结果
cursor.close()
c.closer()
#执行结果
#[{'name': 'zero'}]
#{'@_p1_2': 0}

查看存储过程
show create procedure p1\G;
#\G让字段竖着排
删除存储过程
drop procedure p1;

存储过程跟事务连用:

mysql函数:NOW()获取当前时间,dataformat(sub_time,"%Y-%m")将字段sub_time按年月格式分组

猜你喜欢

转载自www.cnblogs.com/robert-zhou/p/10262605.html
今日推荐