mysql06--视图、触发器、事务(重点)、存储过程、内置函数、流程控制
每日测验
-
默写pymysql模块操作MySQL的代码及主要方法
-
什么是sql注入,如何避免
sql注入有很多种类型,我们只是介绍了其中最具代表性的一种来诠释,
感兴趣的可以自己再去百度查看完整的sql注入种类及解决方式
昨日回顾
- Navicat软件的使用
作为开发 我们使用软件的频率较高 一般不用直接书写sql语句
快速完成库 表的创建 等等...
- 数据库练习题
1 面对复杂的查询题目的时候 不要捉急 sql语句不要想着一口气写完 分步书写
2 只要是涉及到多表查询的时候 肯定用到联表操作和子查询
联表操作 你可以无限制的联N多张表
将两张表的结果起别名 变成了一张表
之后再去另外一张表拼接再起别名
再去拼接...
3 一定要把昨天上课将的练习题自己能够理解并敲出来
- pymysql模块
# 直接安装 无需考虑版本
pip3 install pymysql
import pymysql
conn = pymysql.connect(
host = '127.0.0.1',
port = 3306
user = 'root',
password = '123456', # 简写passwd = '123456'
database = 'db666', # 简写db = 'db666'
charset = 'utf8' # 千万不要加横杆
)
# 括号内不加参数的话 那么查询出来的数据是元组的形式 数据不够明确 容易混乱
# cursor = conn.cursor()
# 字典形式返回数据 数据有具体的描述信息 更加的合理方便
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
sql = 'select * from user'
affect_rows = cursor.execute(sql) # 返回值是当前sql语句执行的受影响的行数
cursor.fetchone() # 只能结果的一条 数据本身
cursor.fetchall() # 拿所有 列表套多个数据
cursor.fetchmany(n) # 指定获取几条
# 上述三个方法在读取数据的时候有一个类似于文件指针的特点
cursor.scroll(1,'relative') # 相对于光标所在的当前位置往后移动
cursor.scroll(1,'absolute') # 相对于数据开头往后移动
# 补充:
1.针对增删改,pymysql需要提交(二次确认)才能真正的修改数据
conn.commit()
2.还可以一次性插入N多条数据
rows = cursor.executemany(sql,[('xxx',123),('ooo',123)])
- sql注入
# 就是利用一些特殊字符 结合软件固定的一些语句句式 非法侵入并违规操作
# sql注入
sql = "select * from user where username='%s' and password='%s'"%(username,password)
# 不要自己拼接
sql = "select * from user where username=%s and password=%s"
execute(sql,(username,password)) # 只能识别%s
今日详细
一.视图
1.什么是视图
视图就是通过查询得到一张虚拟表,然后保存下来,下次可以直接使用
视图的本质就是一张虚拟的表
2.为什么要用视图
如果要频繁的操作一张虚拟表(拼表组成的),你就可以制作成视图 后续直接操作
3.如何操作
# 固定语法
create view 表名 as 虚拟表的查询sql语句
# 具体操作
create view teacher2course as
select * from teacher INNER JOIN course on teacher.tid = course.teacher_id;
注意
1 创建视图在硬盘上只会有表结构 没有表数据(数据还是来自于之前的表)
2 视图一般只用来查询 里面的数据不要继续修改 可能会影响真正的表
3 若原表修改,则对应的视图也会修改
视图到底使用频率高不高呢?
# 不高,当你创建了很多视图之后 会造成表的不好维护
# 总结
视图了解即可 基本不用!!!
二.触发器
在满足对表数据进行增、删、改的情况下,自动触发的功能
使用触发器可以帮助我们实现监控、日志...
触发器可以在六种情况下自动触发 增前 增后 删前 删后 改前 改后
1.基本语法结构
# 创建触发器
create trigger 触发器的名字 before/after insert/update/delete on 表名
for each row
begin
sql语句
end;
# 具体使用 针对触发器的名字 我们通常需要做到见名知意
# 针对增
delimiter $$ # 修改mysql结束符号
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 $$
delimiter ; # 还原mysql结束符号
"""针对删除和修改 书写格式一致"""
# ps:修改MySQL默认的语句结束符 只作用于当前窗口
delimiter $$ 将默认的结束符号由;改为$$
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
);
"""
当cmd表中的记录succes字段是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 ;
# 朝cmd表插入数据
INSERT INTO cmd (
USER,
priv,
cmd,
sub_time,
success
)
VALUES
('jason','0755','ls -l /etc',NOW(),'yes'),
('jason','0755','cat /etc/passwd',NOW(),'no'),
('jason','0755','useradd xxx',NOW(),'no'),
('jason','0755','ps aux',NOW(),'yes');
# 删除触发器
drop trigger tri_after_insert_cmd;
三.事务(掌握)
1.什么是事务
开启一个事务可以包含多条sql语句 这些sql语句要么同时成功
要么一个都别想成功 称之为事务的原子性
2.事务的作用
# 保证了对数据操作的安全性
# eg:还钱的例子
egon用银行卡给我的支付宝转账1000
1 将egon银行卡账户的数据减1000块
2 将jason支付宝账户的数据加1000块
# 你在操作多条数据的时候可能会出现某几条操作不成功的情况
3.事务的四大特性(面试常问)
# ACID
A:原子性
一个事务是一个不可分割的单位,事务中包含的诸多操作
要么同时成功要么同时失败
C:一致性
事务必须是使数据库从一个一致性的状态变到另外一个一致性的状态
一致性跟原子性是密切相关的
I:隔离性
一个事务的执行不能被其他事务干扰
即一个事务内部的操作及使用到的数据对并发的其他事务是隔离的,并发执行的事务之间也是互相不干扰的
D:持久性
也叫"永久性"
一个事务一旦提交成功执行成功 那么它对数据库中数据的修改应该是永久的
接下来的其他操作或者故障不应该对其有任何的影响
4.如何使用事务
# 事务相关的关键字
# 1 开启事务
start transaction;
# 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语句保持一致性 要么同时成功要么同时失败
你就应该考虑使用事务
四.存储过程
存储过程就类似于python中的自定义函数
它的内部包含了一系列可以执行的sql语句,存储过程存放于MySQL服务端中,
你可以直接通过调用存储过程触发内部sql语句的执行
基本使用
create procedure 存储过程的名字(形参1,形参2,...)
begin
sql代码
end;
# 调用
call 存储过程的名字();
1.三种开发模型
第一种
应用程序:程序员写代码开发
MySQL:提前编写好存储过程,供应用程序调用
好处:开发效率提升了 执行效率也上去了
缺点:考虑到人为元素、跨部门沟通的问题 后续的存储过程的扩展性差
第二种
应用程序:程序员写代码开发之外 设计到数据库操作也自己动手写
优点:扩展性很高
缺点:
开发效率降低
编写sql语句太过繁琐 而且后续还需要考虑sql优化的问题
第三种
应用程序:只写程序代码 不写sql语句 基于别人写好的操作MySQL的python框架直接调用操作即可 ORM框架
优点:开发效率比上面两种情况都要高
缺点:语句的扩展性差 可能会出现效率低下的问题
第一种基本不用。一般都是第三种,出现效率问题再动手写sql
2.存储过程具体演示
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;
3.pymysql调用存储过程
import pymysql
conn = pymysql.connect(
host = '127.0.0.1',
port = 3306,
user = 'root',
passwd = '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
"""
cursor.execute('select @_p1_2;')
print(cursor.fetchall())
五.函数
跟存储过程是有区别的,存储过程是自定义函数,函数就类似于是内置函数
NOW(): 当前时间
date_format(): 按指定格式 将时间格式化字符串
('jason','0755','ls -l /etc',NOW(),'yes')
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:21:31'),
('第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 ;
作业
-
复习整理数据相关所有知识点
-
整理今日内容相关博客
-
练习数据库查询题目:https://www.cnblogs.com/Dominic-Ji/p/10875493.html
能做几道做几道,不强制要求。掌握课上讲的题目解决思路即可