http://www.cnblogs.com/linhaifeng/articles/7495918.htmlhtml
试图就是一个虚拟表(非真实存在),本质就是【根据sql语句获取动态的数据集,并为其命名】,用户使用时只须要使用名称便可获取数据集,可将该数据集看成表来使用。python
''' what: 视图是由一张表或多张表的查询结果构成的一张虚拟表 why: 将复杂经常使用的查询结果保留下来重复使用 | 将一张大表拆分红多张小表 语法: create [or replace] view 视图名[(查询字段别名们)] as 查询语句 create view new_emp as (select * from emp); 注: 1.查询字段别名们 要与 查询语句的查询字段对应 2.create or replace: 操做视图没有则建立、有则替换 create or replace view new_emp(id,姓名,工资) as (select id,name,salary from emp where dep_id = 2); 视图的修改:alter 等价于 create or replace, 且语法一致 alter view new_emp(id,姓名,工资) as (select id,name,salary from emp where dep_id = 1); 视图中字段的操做:不容许alter操做字段 alter table new_emp rename new_emp1; alter view new_emp modify id tinyint; 视图中记录的操做:等价于普通表,完成增删改查 update new_emp set 姓名='san' where id = 3; delete from new_emp where id = 3; insert into new_emp(id, 姓名, 工资) values (10, "Bob", 10000); # 操做的是实体表, 虚拟表要从新建立才能拿到最新数据 视图的删除: drop view 视图名; 总结: 虚拟表做用 -- 查询 '''
使用触发器能够定制用户对表进行【增删改】操做时先后的行为(不报包括查询)mysql
''' what:在表发生数据更新时,会自动触发的功能称之为触发器 why:当一个表在发生数据更新时,须要去完成一些操做,能够为具体数据更新的方式添加触发器 语法: delimiter // create trigger 触发器名 before|after insert|update|delete on 表名 for each row begin 须要触发执行的sql代码们 end // delimiter ; # 触发器名: t1_before_insert_tri 注:delimiter是用来修改sql的语句结束标识符 删除触发器:drop trigger 触发器名; '''
# 插入前 CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW BEGIN ... END # 插入后 CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW BEGIN ... END # 删除前 CREATE TRIGGER tri_before_delete_tb1 BEFORE DELETE ON tb1 FOR EACH ROW BEGIN ... END # 删除后 CREATE TRIGGER tri_after_delete_tb1 AFTER DELETE ON tb1 FOR EACH ROW BEGIN ... END # 更新前 CREATE TRIGGER tri_before_update_tb1 BEFORE UPDATE ON tb1 FOR EACH ROW BEGIN ... END # 更新后 CREATE TRIGGER tri_after_update_tb1 AFTER UPDATE ON tb1 FOR EACH ROW BEGIN ... END # 删除触发器 drop trigger tri_after_insert_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 ); # 建立触发器 delimiter // create trigger trigger1 after insert on cmd for each row begin # new就是cmd当前插入的那条记录(对象) 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', '0765', 'ls -l /etc', now(), 'yes'), ('jerry', '0852', 'cat /etc/passwd', now(), 'no'), ('kevin', '0867', 'useradd xxx', now(), 'no'), ('owen', '0912', 'ps aux', now(), 'yes'); # 查看cmd数据信息 select * from cmd; # 查看错误日志表中的记录是否有自动插入 select * from errlog;
触发器用户没法直接调用,而是由对表的【增删改】操做被动引起的程序员
事务用于将某些操做的多个SQL做为原子性操做,一旦有某一个出现错误,便可回滚到原来的状态,从而保证数据库数据完整性sql
''' what:事务是逻辑上的一组操做,要么都成功,要么都失败 why:不少时候一个数据操做,不是一个sql语句就完成的,可能有不少个sql语句,若是部分sql执行成功而部分sql执行失败将致使数据错乱 eg:转帐 => 转入转出均成功,才能认为操做成功 事务的使用: start transaction; --开启事物,在这条语句以后的sql将处在同一事务,并不会当即修改数据库 commit;--提交事务,让这个事物中的sql当即执行数据的操做, rollback;--回滚事务,取消这个事物,这个事物不会对数据库中的数据产生任何影响 事务的四大特性: 1.原子性:事务是一组不可分割的单位,要么同时成功,要么同时不成功 2.一致性:事物先后的数据完整性应该保持一致(数据库的完整性:若是数据库在某一时间点下,全部的数据都符合全部的约束,则称数据库为完整性的状态) 3.隔离性:事物的隔离性是指多个用户并发访问数据时,一个用户的事物不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离 4.持久性:持久性是指一个事物一旦被提交,它对数据的改变就是永久性的,接下来即便数据库发生故障也不该该对其有任何影响 事务的用户隔离级别: 数据库使用者能够控制数据库工做在哪一个级别下,就可与防止不一样的隔离性问题 read uncommitted --不作任何隔离,可能脏读,幻读 read committed --能够防止脏读,不能防止不可重复读,和幻读, Repeatable read --能够防止脏读,不可重复读,不能防止幻读 Serializable --数据库运行在串行化实现,全部问题都没有,就是性能低 修改隔离级别: select @@tx_isolation;--查询当前级别 set[session|global] transaction isolation level ....;修改级别 实例: set global transaction isolation level Repeatable read; 注:修改后从新链接服务器生效 '''
#准备数据 create table account( id int primary key auto_increment, name varchar(20), money double ); insert into account values (1,'owen',10000), (2,'egon',1000), (3,'jerry',1000), (4,'kevin',1000); # egon向owen借1000块钱 # 未使用事务 update account set money = money - 1000 where id = 1; update account set moneys = money + 1000 where id = 2; # money打错了致使执行失败 # 在python中使用事务处理 from pymysql.err import InternalError sql = 'update account set money = money - 1000 where id = 1;' sql2 = 'update account set moneys = money + 1000 where id = 2;' # money打错了致使执行失败 try: cursor.execute(sql) cursor.execute(sql2) conn.commit() # 提交事务 except InternalError: print("转帐失败") conn.rollback()# 回滚操做
存储过程包含了一系列可执行的sql语句,存储过程存放于mysql中,经过调用它的名字可执行其内部的一堆sql语句数据库
优势:服务器
#1. 用于替代程序写的SQL语句,实现程序与sql解耦 #2. 基于网络传输,传别名的数据量小,而直接传sql数据量大
缺点:程序员扩展功能不方便网络
程序与数据库结合使用的三种方式session
#方式一: MySQL:存储过程 程序:调用存储过程 #方式二: MySQL: 程序:纯SQL语句 #方式三: MySQL: 程序:类和对象,即ORM(本质仍是纯SQL语句)
2、建立简单的存储过程(无参)并发
delimiter // create procedure p1() BEGIN select * from blog; INSERT into blog(name,sub_time) values("xxx",now()); END // delimiter ; #在mysql中调用 call p1() #在python中基于pymysql调用 cursor.callproc('p1') print(cursor.fetchall())
3、建立存储过程(有参)
对于存储过程,能够接收参数,其参数有三类: #in 仅用于传入参数用 #out 仅用于返回值用 #inout 既能够传入又能够看成返回值
① in:传入参数
delimiter // create procedure p2( in n1 int, in n2 int ) BEGIN select * from blog where id > n1; END // delimiter ; #在mysql中调用 call p2(3,2) #在python中基于pymysql调用 cursor.callproc('p2',(3,2)) print(cursor.fetchall())
② out:返回值
delimiter // create procedure p3( in n1 int, out res int ) BEGIN select * from blog where id > n1; set res = 1; END // delimiter ; #在mysql中调用 set @res=0; #0表明假(执行失败),1表明真(执行成功) call p3(3,@res); select @res; #在python中基于pymysql调用 cursor.callproc('p3',(3,0)) #0至关于set @res=0 print(cursor.fetchall()) #查询select的查询结果 cursor.execute('select @_p3_0,@_p3_1;') #@p3_0表明第一个参数,@p3_1表明第二个参数,即返回值 print(cursor.fetchall())
③ inout 可传值可返回
delimiter // create procedure p4( inout n1 int ) BEGIN select * from blog where id > n1; set n1 = 1; END // delimiter ; #在mysql中调用 set @x=3; call p4(@x); select @x; #在python中基于pymysql调用 cursor.callproc('p4',(3,)) print(cursor.fetchall()) #查询select的查询结果 cursor.execute('select @_p4_0;') print(cursor.fetchall())
4、执行存储过程
① 在MySQL中执行存储过程
-- 无参数 call proc_name() -- 有参数,全in call proc_name(1,2) -- 有参数,有in,out,inout set @t1=0; set @t2=3; call proc_name(1,2,@t1,@t2)
② 在python中基于MySQL执行存储过程
#!/usr/bin/env python # -*- coding:utf-8 -*- import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1') cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) # 执行存储过程 cursor.callproc('p1', args=(1, 22, 3, 4)) # 获取执行完存储的参数 cursor.execute("select @_p1_0,@_p1_1,@_p1_2,@_p1_3") result = cursor.fetchall() conn.commit() cursor.close() conn.close() print(result)
5、删除存储过程
drop procedure proc_name;
6、小结
''' what:用于完成指定功能的sql语句块,相似于Python中的函数 why:将能指定功能的sql语句块创建成存储过程,不只将sql语句逻辑化了,更是功能化了,那咱们要完成相同的事,只须要重复使用创建的存储过程,不就须要再重复书写sql语句了 # 总结: 存储过程可让sql语句具备 复用性, 从而提升开发效率 语法: delimiter // create procedure 存储过程名( 输入输出类型1 参数名1 参数类型1(宽度), ... , 输入输出类型n 参数名n 参数类型n(宽度) ) begin sql语句块 end // delimiter ; 注: 1.输入输出类型:in | out | inout 2.call 存储过程名(实参们)来调用存储过程 案例: set @res = null; # 定义空值变量, 用来接收存储过程的执行结果 delimiter // create procedure user_info(in b int, in l int, out res char(20)) begin select * from emp limit b, l; set res = 'success'; end // delimiter ; call user_info(2, 3, @res); # 调用存储过程, 传入相应的实参 select @res; # 查看存储过程的执行结果 变量的使用: 1.赋值变量:set @变量名 = 变量值 2.使用变量:@变量名 | select @变量名 3.删除变量:set @变量名 = null 三种开发方式: 1. 业务逻辑 + 存储过程:高执行与开发效率,低耦合 | 不易移植,人员成本高 2. 业务逻辑 + 原生sql:人员成本低 | 开发难度大 3. 业务逻辑 + ORM:高开发效率,对象化操做数据库,可移植 | 性能消耗加大,多表联查、复杂条件会复制化ORM 存储过程的操做: 1.查看 select routine_name, routine_type from information_schema.routines where routine_schema='数据库名'; eg: select routine_name, routine_type from information_schema.routines where routine_schema='db2'; 2.删除 drop procedure [if exists] 数据库名.存储过程名 '''
delimiter // create procedure send_money( out p_return_code char(20) ) begin # 异常处理 declare exit handler for sqlexception begin # error set p_return_code = '错误异常'; rollback; end; # exit 也能够换成continue 表示发送异常时继续执行 declare exit handler for sqlwarning begin # warning set p_return_code = '警告异常'; rollback; end; start transaction; update account set money = money - 1000 where id = 1; update account set money = moneys + 1000 where id = 2; # moneys字段致使异常 commit; # success set p_return_code = '转帐成功'; # 表明执行成功 end // delimiter ; # 在mysql中调用存储过程 set @res=null; call send_money(@res); select @res;