视图
视图的本质就是一张虚拟的表
虚拟表:在硬盘中没有的,通过查询在内存中拼接的表
视图:通过查询得到一张虚拟表,保存下来,下次可以直接使用
为什么要用视图
如果要频繁使用一张虚拟表,可以不用重复查询
如何用视图
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()