视图

  视图的本质就是一张虚拟的表

  虚拟表:在硬盘中没有的,通过查询在内存中拼接的表

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

为什么要用视图

  如果要频繁使用一张虚拟表,可以不用重复查询

如何用视图

  create view  teacher_course as select * from teacher inner join course on teacher.id=course.id;

  create view test_view as select * from t1;

删除视图

  drop view teacher_course;

特点:

  1.每次对视图进行的查询其实都是再次执行了 as 后面的查询语句

  2.可以对视图进行修改,修改会同步到原表

  3.视图是永久存储的,存储的并不是数据而是一条 as sql 语句

强调

  1.在硬盘中,视图只有表结构文件(.frm)没有表数据文件(.idb)其在后台对应的是一条sql语句

  2.视图通常是用于查询,尽量不要修改视图中的数据

 

事务

  事务是一组sql语句集合

事务的特性

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

  2.隔离性:事务之间要相互隔离为了维护数据完整性:你有一张你有一张银行卡 第一次查看了余额发现有1000 开开心心买东西去了
买完东西 回来付钱再一查发现余额不足 , 原来你在第一次查询后你的媳妇把钱转走了
    上面这个问题称为不可重复读
    如何避免 我在查的时候你不能修改 查询和 修改不能同时进行

    因为并发访问导致的一些问题

    1.脏读:一个事务读到了另一个事务未提交的数据 查询之前要保证所有的更新都已经完成

    2.幻读: 一个查询事务没有结束时 数据被另一个事务执行 insert delete

    3.不可重复读: 一个事务在查询 另一个事务在 update

    四种隔离级别

      读未提交

      读已提交

      可重复读 默认

      串行化

  3.一致性

    当事务执行后,所有的数据都是完整的(外键约束 非空约束)

  4.持久性

    一旦事务提交 数据就永久保存

事务是一堆sql语句的集合,它们是原子性的要么全部执行,要么都不执行

mysql是默认开启自动提交的一条sql语句就是一个单独的事务

pymysql默认是不自动提交的需要用commit来提交修改

start transacton;开启一个事务

commit 提交事务

rollback 回滚事务

使用事务

create table user(
id int primary key auto_increment,
name char(32),
balance int
);

insert into user(name,balance)
values
('wsb',1000),
('egon',1000),
('ysb',1000);

try:
    update user set balance=900 where name='wsb'; #买支付100元
    update user set balance=1010 where name='egon'; #中介拿走10元
    update user set balance=1090 where name='ysb'; #卖家拿到90元
except 异常:
    rollback;   #如果异常,回滚到前一个状态,即balance都为1000
else:
commit;   #如果无异常,修改数据库(硬盘上的数据)

 

1.开启一个事务
begin  | start transaction 
sql........
2.事务执行完毕后 使用commit来提交 一旦提交就不可恢复了
commit

3.在事务还未提交时我们可以使用rollback来回滚 默认回滚到事务开始前的状态
rollback

创建一张银行账户表 包含 id 账号 姓名 余额
CREATE table account(id int primary key auto_increment,number char(20),name char(10),money double);


为事务创建保存点 保存点就像游戏中的记录 你可回滚到指定的一个点
savepoint  point_name;

回滚至一个保存点
rollback to point_name;

如果有多个保存点 我们可以 多次往回回滚 但是 不能往下前进;因为 一旦回滚了 那么响应的语句也就不存在了;

默认情况下 每一条sql都是一个单独的事务 默认自动提交
也就是一旦执行就不可恢复 
如果想要手动提交 将自动提交关闭
查看是否开启
show variables like 'autocommit';
设置开启状态
set autocommit = 1 | 0;  打开 | 关闭

 mysql中的变量分为三种

  1.全局变量  @@代表系统变量 系统以及定好的变量

  2.会话级变量  @代表用户变量 自己定义的变量

  3.局部变量

查看当前隔离级别

  select @@global.tx_isolation,@@tx_isolation;

  设置隔离级别分两种

  全局与会话级

  set global tx_isolation = "read-committed";

  set tx_isolation="read-committed";

 

存储过程

  在mysql 中函数时不能单独使用的,必须放在sql语句中使用;但存储过程是可以单独使用的

  存储过程包含了一系列可执行的sql语句,存储过程存放于mysql中,通过调试它的名字可以执行其内部的一堆sql

  使用场景:通常情况下 我们需要把业务逻辑放在客户端处理,例如:注册新用户

  1.发起一个请求,将要注册的账户名发给服务器进行查询

  2.服务器将查询结果返回给客户端

  3.客户端根据结果判断是否可以注册

  4.如果可以,则再发起请求 想数据库中插入数据

  5.服务器返回插入结果

  需要与数据库服务器进行多次通讯,如果网络状态很差,将会需要很长时间,这是就可以使用存储过程,来将原本需要在客户端处理的逻辑放在数据库服务器中,服务器只需要返回一个注册成功或失败即可,大大减少了通讯次数

  缺点:不同数据库的存储过程大不相同,不可移植,重用性太低

三种开发模型

  1.(如果不考虑非技术因素,各方面效率最高的选择;但考虑到实际情况,一般不被选择)

    应用程序:需要开发应用程序的逻辑

    mysql处理逻辑,mysql编写好存储过程,以供应用程序调用

    优点:开发效率,执行效率都高

    缺点:考虑到人为因素,部门沟通等问题,会导致扩展性差

  2.应用处理逻辑

      应用程序:除了开发应用程序的逻辑,还需要编写原生sql

    优点:比方式1 扩展性高(非技术性的)

    缺点:

      1.开发效率、执行效率都不如方式1

      2.编写原生sql太过于复杂,而且需要考虑到sql语句的优化问题

  3.使用 ORM(object relation map) 对象关系映射(考虑到非技术因素,最常见的选择)

    应用程序:开发应用程序的逻辑,不需要编写原生sql,基于别人编写好的框架来处理数据,ORM(object relationship matching)

    优点:不用再编写纯生sql,这意味着开发效率比方式2 高,同时兼容方式2扩展性高的好处

    缺点:执行效率连方式2都比不过

  

一: 创建存储过程
create procedure pro_name(p_Type p_name data_type)
begin
sql语句......
end

p_type 表示参数输入输出的类型 有 in out inout;
p_name 参数名
data_type 数据类型 int char ....

注意在过程中 一行结束使用分号
需求 编写存储过程 实现 将两数相加并输出结果
create procedure add_pro(in a int,in b int,out c int)
begin
  //注释使用双斜杠
  //要为变量赋值 需要使用set 关键字
  set c = a + b;
end + 结束符

由于 mysql默认结束符就是分号  而存储过程也是用分号来表示结束 那么这时 mysql就分不清 到底哪个分号才一行结束
方案:更换 结束符
delimiter + 结束符;
delimiter ;;

* 在存储过程中可以插入任意的sql语句


二: 调用存储过程
使用关键字 call
例如: call add_pro(参数);
如果有返回值 需要用变量接收
定义变量的方式
set @变量名 = 值; 定义的变量在断开连接后被释放

三: if语句的使用
if 条件  then
语句;
end if;
第二种 if elseif
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 语句  大体意思与Swtich一样的  你给我一个值 我对它进行选择 然后执行匹配上的语句
语法:
CASE 变量名
when 值1 then 语句1;
when 值2 then 语句2;
when 值3 then 语句3;
else 语句4;
end case;

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语句  用来执行循环
语法
WHILE 条件 DO
语句.....
end 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语句  也是用来循环的 没有条件 需要自己定义结束语句
语法:
循环名: LOOP
语句.....
end LOOP 循环名; 
leave 关键字用于跳出某个循环 需要指定循环的名字 loop 专用
iterate 跳过本次循环 loop专用
例如: leave aloop;


输出十次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
语法:
repeat 
语句......;
until 结束条件
end repeat;

输出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 showjishu2()
begin
declare i int default 0;
aloop: loop
#如果i的值大于等于101时结束循环
if i >= 101 then leave aloop; end if;
#如果取余2 = 0 就跳过本次
if i % 2 = 0 then iterate aloop; end if;
/*输出i*/
select i;
#将i的值+1;
set i = i + 1;
/*循环结束*/
end loop aloop;
end

create procedure showjishu1()
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

 

存储过程使用
a、直接在mysql中调用
set @res=10   #mysql中变量的定义要用@abc的形式
call p1(2,4,@res);

select @res;  #查看结果

b、在python程序中调用
import pymysql

conn=pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123',
    charset='utf8',
    database='db42'
)

cursor=conn.cursor(pymysql.cursors.DictCursor)
cursor.callproc('p1',(2,4,10)) #@_p1_0=2,@_p1_1=4,@_p1_2=10  #pymysql帮助对传入变量进行以上变形
print(cursor.fetchall())
cursor.execute('select @_p1_2;')  #查看返回值,确认执行结果
print(cursor.fetchone())

cursor.close()
conn.close()

事务的使用 (事务+存储过程)
delimiter //
create PROCEDURE p5(
    OUT p_return_code tinyint
)
BEGIN
    DECLARE exit handler for sqlexception  #如果出现错误,执行
    BEGIN
        -- ERROR
        set p_return_code = 1;
        rollback;
    END;

    DECLARE exit handler for sqlwarning    #如果出现警告,执行
    BEGIN
        -- WARNING
        set p_return_code = 2;
        rollback;
    END;

    START TRANSACTION;                     #事务的应用
        update user set balance=900 where id =1;
        update user123 set balance=1010 where id = 2;
        update user set balance=1090 where id =3;
    COMMIT;

    -- SUCCESS
    set p_return_code = 0; #0代表执行成功

END //
delimiter ;

#在python中调用存储过程
import pymysql

conn=pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123',
    charset='utf8',
    database='db44'
)

cursor=conn.cursor(pymysql.cursors.DictCursor)
cursor.callproc('p6',(100,)) #@_p5_0 = 100
cursor.execute('select @_p6_0')
print(cursor.fetchone())

cursor.close()
conn.close()