视图
视图是有一条sql语句的查询结果构成的虚拟表
其不是物理存在的 使用方式与普通表相同
创建视图语法
create [or replace] view view_name as sql 语句;
修改
alter view view_name as sql 语句;
删除
drop view view_name;
视图的作用
1.简化sql语句的编写
案例:
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), address varchar(100) ); insert into stu_info values(1,'二班','安徽'),(2,'二班','湖南'),(3,'三班','黑龙江');
#创建视图包括 编号 学生的姓名和班级 create view stu_view (编号,姓名,班级) 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_view;
2.限制可查看的数据
可以使用权限来完成 权限到某个库 的某个一个表的某一个字段
视图的特点:
对于视图的增删改查 都会同步到原始表
每一次视图的查询 本质上都是执行了之前创-建视图时 指定的sql语句
对于原始表的修改 也能在视图中查看到 前提是你修改的数据 包含在创建视图时指定的sql语句中
案例:
create table salary_info( id int primary key, name char(10), salary double, dept char(10) ); insert into salary_info values (1,"刘强东",900000,"市场"), (2,"马云",800090,"市场"), (3,"李彦宏",989090,"财务"), (4,"马化腾",87879999,"财务");
#创建市场部视图 create view info as select * from salary_info where dept='市场'; #查看市场部视图 select * from info;
触发器
是一段与某个表有关的mysql程序
当达到某种条件,触发某个东西的执行
条件:
时间点 before |after
具体事件 update |delete | insert
new|old old new
达到条件后:
自动执行一段mysql程序
删除触发器
语法:
drop trigger trigger_name;
作用:
做一个博客系统
需要在执行更新 自动记录更新时间 以及更新具体内容
总的来说就是可以帮你在一个表被修改时 做一些额外操作
语法:
create trigger name after delete on tablename for each row
begin
# 具体要执行的操作
end
在触发器中有两个隐藏对象
new(新的数据)和old(旧的数据)
案例:
创建一个博客表
id int title char content longtext commit_time timestamp
更新记录表
id int content longtext update_time timestamp b_id int
create table blog(id int primary key auto_increment,content text,b_id int,foreign key(b_id) references blog(id),update_time timestamp); create table blogs(id int primary key auto_increment,content text,b_id int,foreign key(b_id) references blog(id),update_time timestamp);
创建触发器 delimiter // create trigger t1 after update on blog for each row begin insert into update_log values(null,new.content,now(),new.id); end // delimiter ; #查询数据 select *from users;
在blog表发生了update事件时 要自动将更新后的数据插入记录表
# 重定义结束符为//因为触发器中包含;而分号是默认的结束符
案例:
存储的是 什么时间执行了 什么指令 结果是什么?
errlog 表 存储的是 所有执行失败的指令信息
当数据插入cmd表时 判断 如果 success 为no 就将这个信息插入errlog表中
准备数据
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 if new.success = "no" then insert into errlog values(null,new.cmd,new.sub_time); end if; end// delimiter ;
INSERT INTO cmd ( USER, priv, cmd, sub_time, success ) VALUES ('jerry','0755','ls -l /etc',NOW(),'yes'), ('jerry','0755','cat /etc/passwd',NOW(),'no'), ('jerry','0755','useradd xxx',NOW(),'no'), ('jerry','0755','ps aux',NOW(),'yes');
select *from errlog;
事务
事务是逻辑上一组sql语句的集合
特点是:一个事务的所有sql语句 要么全部执行成功 要么全部失败
事务最强大的地方在于
当发生一些不不可控因素时(断电,系统崩溃,网络中断),可以保住数据是完整的(原子性)
原子性
一个事务是一个整体 不可拆分要么都成功要么都失败
一致性
一个事务无论成功或失败 相关数据的约束一定是完整的
隔离性
与效率息息相关
两个事务之间相互独立
read uncommitted 不做任何隔离,可能脏读(读取到其他事务未提交的数据)
read committed 可以防止脏读,不能防止不可重复(并发修改)和幻读(并发添加和修改)
对同一条记录同一事务的两次查询结果不一致称之为不可重复读
原因是:一个事务在查询数据 另一个事务在添加/删除数据
Repeatable_read 可以防止脏读,不可重复读(加锁保证查询事务和更新事务不能并发),不能防止幻读
insert/delete 和查询事务可以并发执行
Serializable 数据库运行在串行化实现,所有问题都没有,就是性能低
查看当前隔离级别
select * from @@tx_isolation
设置新的隔离级别
set global transaction isolation level Serializable
永久性
一个事务一旦提交,就是永久性的 无法回滚
事务在pymysql中的使用
pymysql封装了事务的开启 我们需要做的就是在执行成功后提交事务
一些客户端中默认是没有事务的 例如cmd中的mysql客户端
注意:如果在创建连接时 将自动提交设置为了True则不会再开启事务一般不要改这个默认选项
import pymysql conn = pymysql.connect(host='127.0.0.1', user='root', password='123321', database='day45') cursor = conn.cursor(pymysql.cursors.DictCursor) try: sql1 = 'update account set money=money-100 where id=1' sql2 = 'update account set money=money+100 where id=2' cursor.execute(sql1) cursor.execute(sql2) conn.commit() print('转账成功!') except Exception as e: print(type(e), e) # cursor.scroll()#发生错误就回滚
存储过程
一个存储过程中包含任意sql语句,以及流程控制,事务等待。。。
简单的就是说 将一系列较为复杂的逻辑封装到了mysql中
好处:
例如注册功能
接收用户名 密码
判断用户名是否存在 需要编写一条sql语句 传给服务器 服务器执行完毕返回结果
客户端在发起请求 把用户名和密码穿给服务器
经历了至少2次网络传输
如果使用存储过程就可以一次性将用户名和密码传给服务器等到接收结果即可
降低了网络传输 提高了效率
弊端:学习成本高,运营成本高,沟通成本高 三高
正常开发中有三种常见方式完成数据库相关操作
1.应用程序开发者 只关注逻辑 数据相关的逻辑交给存储过程
优点:优化了网络传输 耦合度降低
弊端:学习成本高,运营成本高,沟通成本高 三高 存储过程移植性非常差每种数据语法都不同
2.应用程序开发者 不仅关注业务逻辑 还需要编写原生的sql语句
优点:一个负责人所有 没有沟通成本
缺点:sql语句编写繁琐 导致开发效率降低
3.应用程序开发者 仅关注业务逻辑 把sql语句相关的交给ORM(对象关系隐射 帮你封装了增删改查 自动生成sql语句)
优点:开发效率提高了
缺点:执行效率较低
摩尔定律 每过18个月 cpu 计算能力 至少翻一番
create procedure p1(type 参数名 数据类型) type :in 输入参数 out输出参数 inout既能输出又能输入 delimiter // create procedure p1(in a double,in b double) begin select *from account where money >= a and money <= b; end// delimiter ;
存储过程 与函数的区别
函数仅仅是一个单纯工具 与数据无关 所以函数中不能出现sql语句
存储过程 既可以包含mysql的逻辑代码 也能包含sql 语句
delimiter // create procedure p2(in a double,in b double,out res char(20)) begin select *from account where money >= a and money <= b; set res = "success"; end// delimiter ;
#删除 drop procedure 过程名称; #查看所有 select `name` from mysql.proc where db = 'db02' and `type` = 'PROCEDURE';
案例1:
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), address varchar(100) ); insert into stu_info values(1,'二班','安徽'),(2,'二班','湖南'),(3,'三班','黑龙江');
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 ; #调用存储过程 call p1(70,80,@res); #查看执行结果 select @res;
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())
模拟转账
delimiter // create PROCEDURE p5(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 = money - 1000 where id = 1; # moneys字段导致异常 COMMIT; # SUCCESS set p_return_code = 0; #0代表执行成功 END // delimiter ; #在mysql中调用存储过程 call p5(@res); select @res;
import pymysql conn = pymysql.connect(host='127.0.0.1', user='root', password='123321', database='day45') cursor = conn.cursor(pymysql.cursors.DictCursor) # 调用存储过程 如果是一个输出out参数 随便给个值就行 # cursor.callproc('p2',(500,2000,0)) # # pymysql会自动定义变量@_存储过程名称_参数索引 # #分别是:@_p2_0 @_p2_1 @_p2_2 # # # 获取结果 # # print(cursor.fetchall()) # # # 获取存储过程的结果 # # cursor.execute('select @_p2_2') # # print(cursor.fetchall()) # 调用 cursor.callproc('p5',(0,)) # 获取结果是否有结果取决于存储过程中是否select语句 print(cursor.fetchall()) # 通过查询变量获取执行状态 cursor.execute('select @_p5_0') print(cursor.fetchall())
函数
内置函数
日期相关
CURRRNT_DATE() | 当前日期 |
CURRENT_TIME() | 当前时间 |
CURRENT_TIMESTAMP | 当前时间戳 |
DATE_ADD(date2,INTERVAL d_value d_type) | 在date2中加上日期或时间 |
DATE_SUB(date2,INTERVAL d_value d_type) | 在date2上减去一个时间 |
DATEDIFF(date1,date2) | 两个日期差(结果是天) |
TIMEDIFF(date1,date2) | 两个时间差(多少小时多少分钟多少秒) |
NOW() | 当前时间 |
YEAR|Month|DATE(datetime) | 返回datetime的某个部分 |
字符串相关
CHARSET(str) | 返回字串字符集 |
CONCAT(string2[,....]) | 连接字串 |
INSTR(string,substring ) | 返回substring在string中出现的位置,没有返回0 |
UCASE(string2) | 转换成大写 |
LCASE(string2) | 装换成小写 |
LEFT(string2,length) | 从string2中的左边起取length个字符 |
LENGTH(string) | string长度 |
REPLACE(str,search_str,replace_str) | 在str中replace_str替换search_str |
STRCMP(string1,string2) | 逐字符比较两字串大小 |
SUBSTRING(str,position[,length]) | 从str的position开始,取length个字符 |
LTRIM(string2)RTRIM(string2)trim | 去除前端空格或后端空格 |
数字相关
ABS(number2) | 绝对值 |
BIN(decimal_number) | 十进制转二进制 |
CEILING(number2) | 向上取整 |
CONV(number2,from_base,to_base) | 进制转换 |
FLOOR(number2) | 向下取整 |
FORMAT(number,decimal_places) | 保留小数位数 |
HEX(DecimalNumber) | 转十六进制 |
LEAST(number,number2[,...]) | 求最小值 |
MOD(numberator) | 求余 |
RAND([seed]) | RAND([seed]) |
其他函数
USER() | 查询用户 |
DATABASE() | 数据库名称 |
MD5(str) | 为字符串算出一个MD5 128比特检查和,通常用于对应用程序使用到表的某个字段(比如用户密码)加密 |
PASSWORD(str) | 从原文密码str计算并返回密码字符串,通过用于对mysql数据库的用户密码加密 |
DATE_FORMAT(str,fmt) | 将一个日期按照某个格式输出 |
自定义函数
#语法 CREATE FUNCTION f_name(paramters) returns dataType; return value;
create function addfuntion(a int,b int) returns int return a + b; 54asd#执行函数 select addfuntion(1,1);
mysqldump -u -p db_name [table_name,,,] > fileName.sql #案例 #示例: #单库备份 mysqldump -uroot -p123 db1 > db1.sql mysqldump -uroot -p123 db1 table1 table2 > db1-table1-table2.sql #多库备份 mysqldump -uroot -p123 --databases db1 db2 mysql db3 > db1_db2_mysql_db3.sql #备份所有库 mysqldump -uroot -p123 --all-databases > all.sql
使用 mysql 进行恢复
mysql -u -p < filename.sql;
2.不用退出数据库
2.1 创建空数据库
2.2选择数据库
2.3然后使用source filename; 来进行还原
use db1; source /root/db1.sql
务必保证在相同版本之间迁移 # mysqldump -h 源IP -uroot -p123 --databases db1 | mysql -h 目标IP -uroot -p456
if 条件 then 语句; end if; 第二种 if elseif if 条件 then 语句1; elseif 条件 then 语句2; else 语句3; end if;
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
#大体意思与Swtich一样的 你给我一个值 我对它进行选择 然后执行匹配上的语句 语法: 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
#循环输出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
#没有条件 需要自己定义结束语句 语法: 输出十次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
#类似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