今天学习了数据库的视图、触发器、事务、存储过程、函数、数据备份与恢复和流程控制java
1、视图python
什么是视图mysql
视图由一张表或多张表的查询结构构成的一张虚拟表面试
为何使用视图sql
当咱们在使用多表查询时,咱们的sql语句可能会很是的复杂,若是每次都编写一遍sql的话无疑是一件麻烦的事情,这时候就可使用视图来避免屡次编写sql的问题;数据库
简单的说能够帮咱们节省sql的编写,视图的另外一个做用是,能够不一样的视图来展现开放不一样数据的访问网络
例如,同一张工资表,老板能够查看所有,部门主管能够查看该部门全部人,员工只能看本身的一条记录session
使用方法数据结构
建立视图并发
CREATE [OR REPLACE] VIEW view_name [(colum_list)] AS select_statement
加上OR REPALCE 时若是已经存在相同视图则替换原有视图
column_list指定哪些字段要出如今视图中
注意:因为是一张虚拟表,视图中的数据实际上来源于其余表,因此再说视图中的数据不会出如今硬盘上
使用视图
视图是一张虚拟表 因此使用方式与普通标没有任何区别
查看视图
1.desc view_name; //查看数据结构
2.show create view view_name; //查看 建立语句
修改视图
alter view_name select_statement
删除视图
drop view view_name
案例1:简化多表sql语句
#准备数据 create database db02; use db02 create table student( s_id int(3), name varchar(20), math float, chinese float ); insert into student values(1,'tom',80,70), (2,'jack',80,80), (3,'rose',60,75); create table stu_info( s_id int(3), class varchar(50), addr varchar(100) ); insert into stu_info values(1,'二班','安徽'), (2,'二班','湖南'), (3,'三班','黑龙江'); #建立视图包含 编号 学生的姓名 和班级 create view stu_v (编号,姓名,班级) as select student.s_id,student.name, stu_info.class from student,stu_info where student.s_id = stu_info.s_id; #查看视图中的数据 select * from stu_v;
案例2:隔离数据
#建立工资表 create table salarys( id int primary key, name char(10), salary double, dept char(10) ); insert into salarys values(1,"刘强东",900,"市场"), (2,"马云",800,"市场"), (3,"李彦宏",700,"财务"), (4,"马化腾",600,"财务"); #建立市场部视图 create view dept_sc as select * from salarys where dept = "市场"; select * from dept_sc;
注意: 对视图数据的inser update delete 会同步到原表中,但因为视图多是部分字段,不少时候会失败
总结:mysql能够分担程序中的部分逻辑,但这样一来后续的维护会变得更麻烦
若是须要改表结构,那意味着视图也须要相应的修改,没有直接在程序中修改sql来的方便
2、触发器
什么是触发器
触发器是一段与表有关的mysql的程序 当这个表在某个时间点发生了某种事件时 将会自动执行相应的触发器程序
什么时候使用触发器
当咱们想要在一个表记录被更新时作一些操做时就可使用触发器
可是咱们彻底能够在python中来完成这个事情,由于python的扩展性更强,语法更简单
建立触发器
语法:
CREATE TRIGGER t_name t_time t_event ON table_name FOR EACH ROW
begin
stmts.....
end
支持的时间点(t_time):时间发生前和发生先后 before|after
支持的事件(t_event):update insert delete
在触发器中能够访问到将被修改的那一行数据 根据事件不一样 能访问也不一样 update 可用OLD访问旧数据 NEW访问新数据 insert可用NEW访问新数据 delete 可用OLD访问旧数据
能够将NEW和OLD看作一个对象其中封装了这列数据的全部字段
案例:
有cmd表和错误日志表,需求:在cmd执行失败时自动将信息存储到错误日志表中
#准备数据 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 ); #建立触发器 delemiter // create trigger trigger1 after insert on cmd for each row begin if new.success = 'no' then insert into errlog values(null,new.cmd,new.sub_time); end if; end // delimiter; #往表cmd中插入记录,触发触发器,根据IF的条件决定是否插入错误日志 INSERT INTO cmd( USER, priv, cmd, sub_time, success ) VALUES ('egon','0755','ls -l/etc',NOW(),'yes'), ('egon','0755','cat/etc',NOW(),'no'), ('egon','0755','useradd xxx',NOW(),'no'), ('egon','0755','ps aux',NOW(),'yes'); # 查看错误日志表中的记录是否有自动插入 select * from errlog;
delimiter 用于修改默认的行结束符,因为在触发器中有多条sql语句他们须要使用分号来结束,可是触发器是一个总体,因此咱们须要先更换默认的结束符,在触发器编写完后将结束符设置回分号
主要:
外键不能触发时间 主表删除了某个主键 从表也会相应删除 可是并不会执行触发器 触发器中不能使用事物 相同时间点的相同事件的触发器 不能同时存在
删除触发器
语法:
drop trigger trigger_name;
案例:
drop trigger trigger1;
一样的这种需求咱们彻底能够在python中来完成!mysql最想完成的事情是将全部能处理的逻辑所有放到mysql中,那样一来应用程序开发者的活儿就变少了,相应的数据库管理员的工资就高了,惋惜大多中小公司都没有专门的DBA;
3、事务
什么是事务
事务是逻辑上的一组操做,要么都成功,要么都失败
为何须要事务
不少时候一个数据操做,不是一个sql语句就完成的,可能有不少个sql语句,若是部分sql执行成功而部分sql执行失败将致使数据错乱!
例如转帐操做,
1.从原有帐户减去转帐金额
2.给目标帐户加上转帐金额
若中间忽然断电了或系统崩溃了,钱就不知去向了~
使用事物
start transaction; #开启事物,在这条语句以后的sql将处在同一事务,并不会当即修改数据库
commit; #提交事务,让这个事务中的sql当即执行数据的操做,
rollback; #回滚事务,取消这个事务,这个事务不会对数据库中的数据产生任何硬性
案例:转帐过程当中发生异常
#准备数据 create table account( id int primary key auto_increment, name varchar(20), money double ); insert into account values(1,'赵大儿子',1000), (2,'刘大牛',1000), (3,'猪头三',1000), (4,'王进',1000), (5,'黄卉',1000); #赵大儿子给刘大牛转帐1000块 # 未使用事务 update account set money = money - 1000 where id = 1; update account set moneys = money - 1000 where id = 1; #money打错了致使执行失败 # 在python中使用事务处理 sql = 'update account set money = money - 1000 where id = 1;' sql2 = 'update account set moneys + 1000 where id = 2;' #money打错了致使执行失败 try: cursor.execute(sql) cursor.execute(sql2) conn.commit() except: conn.rollback()
注意:事务的回滚的前提是能捕捉到异常,不然没法决定什么时候回滚,Python中很简单就实现了,另外mysql中须要使用存储过程才能捕获异常!
事务的四个特性:
原子性:
事务是一组不可分割的单位,要么同时成功,要么同时不成功
一致性:
事务先后的数据完整性应该保持一致,(数据库的完整性:若是数据库在某一时间点下,全部的数据都符合全部约束,则称数据库为完整性的状态);
隔离性:
事务的隔离性是指多个用户并发访问数据时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要互相隔离
持久性:
持久性是指一个事务一旦被提交,它对数据的改变就是永久性的,接下来即便数据库发生故障也不该该对其有任何影响
事务的用户隔离级别:
数据库使用者能够控制数据库工做在哪一个级别下,就能够防止不一样的隔离性问题
read uncommitted --不作任何隔离,可能脏读,幻读
read committed --能够防止脏读,不能防止不可重复读,和幻读,
Repeatable read --能够防止脏读,不可重复读,不能防止幻读
Serializable -- 数据库运行在串行化实现,全部问题都没有,就是性能低
修改隔离级别:
select @@tx_isolation; --查询当前级别
set[session|global] transaction isolation level ....;修改级别
实例:
set global transaction isolation level Repeatable read;
4、存储过程
什么是存储过程
存储过程是一组任意的sql语句集合,存储在mysql中,调用存储过程时将会执行其包含的全部sql语句;与python中函数相似;
为何使用存储过程
回顾触发器与视图都是为了简化应用程序中sql语句的书写,可是仍是须要编写,而存储过程当中能够包含任何的sql语句,包括视图,事务,流程控制等,这样一来,应用程序能够从sql语句中彻底解放,mysql能够替代应用程序完成数据相关的逻辑处理!
三种开发方式对比
1.应用程序仅负责业务逻辑编写,全部与数据相关的逻辑都交给mysql来完成,经过存储过程(推荐使用)
优势:
应用程序与数据处理完解耦合,一堆复杂的sql被封装成了一个简单的存储过程,考虑到网络环境因素,效率高
应用程序开发者不须要编写sql语句,开发效率高
缺点:
python语法与mysql语法区别巨大,学习成本高
而且各类数据库的语法大不相同,因此移植性很是差
应用程序开发者与BDA的跨部门沟通成本高,形成总体效率低
2.应用程序不只编写业务逻辑,还须要编写全部的sql语句
优势:扩展性高,对于应用程序开发者而言,扩展性和维护性相较于第一种都有所提升
缺点:sql语句过于复杂,致使开发效率低,且须要考虑sql优化问题
3.应用程序仅负责业务逻辑,sql语句的编写交给ORM框架,(经常使用解决方案)
优势:应用程序开发者不须要编写sql语句,开发效率高
缺点:执行效率低,因为须要将对象的操做转化为sql语句,且须要经过网络发送大量sql
建立存储过程
create procedure pro_name(p_Type p_name data_type)
begin
sql 语句......流程控制
end
p_type 参数类型
in 表示输入参数
out 表示输出参数
inout 表示既能输入又能输出
p_name 参数名称
data_type 参数类型 能够是mysql支持的数据类型
案例:使用存储过程完成对student表的查询
delimiter // create procedure p1(in m int, in n int,out res int) begin select * from student where chinese > m and chinese < n; #select * from student where chineseXXX > m and chinese < n; 修改错误的列名以检测执行失败 set res = 100; end// delimiter ; set @res = 0; #调用存储过程 call p1(70,80,@res); #查看执行结果 select @res;
须要注意的是,存储过程的out类参数必须是一个变量,不能是值;
在python中调用存储过程
import pymysql #创建链接 conn = pymysql.connect( host = '127.0.0.1', user = 'root', password = 'admin', database = 'db02' ) #获取游标 cursor = conn.cursor(pymysql.cursors.DictCursor) #调用存储过程 cursor.callproc('p1',(70,80,0)) #p1为存储过程名 会自动为每一个值设置变量,名称为@_p1_0,@_p1_1,@_p1_2 #提取执行结果是否有结果取决于存储过程当中的sql语句 print(cursor.fetchall()) #获取执行状态 cursor.execute('select @_p1_2') print(cursor.fetchone())
此处pymysql会自动将参数都设置一个变量因此能够直接传入一个值,固然值若是做为输出参数的话,传入什么都无所谓~
删除存储过程
drop procedure 过程名称;
修改存储过程意义不大,不如删除重写!
查看存储过程
#当前库全部存储过程名称 select 'name' from mysql.proc where db = 'db02' and 'type' = 'PROCEDURE'; #查看建立语句 show create procedure p1;
存储过程当中的事务应用
存储过程当中支持任何的sql语句包括事务!
案例:模拟转帐中发送异常,进行回滚
delimiter // create PROCEDURE p5( out p_return_code tinyint ) begin DECLARE exit handler for sqlexception begin set p_return_code = 1; rollback; end #exit 也能够换成 continue 表示发送异常时继续执行 declare exit handler for sqlwarning begin set p_return_code = 2; rollback; end start transaction; update account set money = money - 1000 where id = 1; update account set moneys = money - 1000 where id = 1; #moneys字段致使异常 commit; set p_return_code = 0; #0表明执行成功 end // delimiter ; #在mysql中调用存储过程 set @res = 123; call p5(@res); select @res;
总结:抛开沟通成本,学习成本,存储过程无疑是效率最高的处理方式,面试会问(划重点!!!),一些公司也有一些现存的存储过程,重点掌握!
5、函数
自定义函数
语法:
CREATE FUNCTION f_name(paramters) returns dataType return value;
说明:paramters 只能是in 输入参数 参数名 类型 必须是返回值 不能加begin和end returns 后面是返回值的类型 这里不加分号 return后面是返回的值
案例:将两数相加
create function addfuntion(a int,b int) returns int return a+ b; #执行函数 select addfuntion(1,1)'
注意:函数只能返回一个值 函数通常不涉及数据的增删改查 就是一个通用的功能 调用自定义的函数 与调用系统的一致
不须要call 使用select可得到返回值 函数中不能使用sql语句 就像在java中不能识别sql语句同样
6、数据备份与恢复
使用mysqldump程序进行备份
mysqldump -u -p db_name [tabke_name,,,] > fileName.sql
能够选择要备份哪些表 若是不指定表明所有备份
#实例: #单库备份 mysqldump -uroot -proot db1 > db1.sql mysqldump -uroot -proot db1 table1 table2 > db1-table1-table2.sql #多库备份 mysqldump -uroot -proot --databases db1 db2 mysql db3 > db1_db2_mysql_db3.sql #备份全部库 mysqldump -uroot -proot --all-databases > all.sql
使用mysql进行恢复
1.退出数据库后
mysql -uroot -proot < filename.sql;
2.不用退出数据库
2.1 建立空数据库
2.2 选择数据库
2.3 而后使用 source filename; 来进行还原
use db1;
source /root/db1.sql
数据库迁移
务必保证在相同版本之间迁移 #mysqldump -h 源IP -uroot -proot --databases db1|mysql -h 目标IP -uroot -proot
7、流程控制
if 语句的使用
if 条件 then语句;end if; 第二种 if else if 条件 then 语句1;elseif 条件 then 语句2;else 语句3;end if;
案例:编写过程 实现 输入一个整数type范围 1-2 输出 type = 1 or type = 2 or type = other;
create procedure showType(in type int,out result char(20)) begin if type = 1 then set result = 'type = 1'; elseif type = 2 then set result = 'type = 2'; else set result = 'type = other'; end if; end
CASE 语句
大致意思与switch同样的 你给我一个值 我对他进行选择 而后执行匹配上的语句 语法:
create procedure caseTest(in type int) begin CASE type when 1 then select 'type = 1'; when 2 then select 'type = 2'; else select 'type = other'; end case; end
定义变量
declare 变量名 类型 default 值; 例如:declare i int default 0;
WHILE 循环
循环输出10次hello mysql create procedure showHello() begin declare i int default 0; while i < 10 do select 'hello mysql'; set i = i+1; end while; end
LOOP循环
没有条件 须要本身定义结束语句 语法:
输出十次hello mysql; create procedure showloop() begin declare i int default 0; aloop:LOOP select 'hello loop'; set i = i + 1; if i > 9 then leave aloop; end if; end LOOP aloop; end
REPEAT循环
#相似 do while #输出10次hello repeat create procedure showRepeat() begin declare i int default 0; repeat select 'hello repeat'; set i = i + 1; until i > 9 end repeat; end #输出0-100之间的奇数 create procedure showjishu() begin declare i int default 0; aloop: loop set i = i + 1; if i >= 101 then leave aloop; end if; if i % 2 = 0 then iterate aloop; end if; select i; end loop aloop; end