zoukankan      html  css  js  c++  java
  • 视图、触发器、事务、存储过程、函数、数据备份与恢复、流程控制

    视图
    视图是有一条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
    );
    创建cmd和errlog表
    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()#发生错误就回滚
    事务在pymysql的用法
    存储过程
    一个存储过程中包含任意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 ;
    创建存储过程语法2
    #删除
    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;
    在mysql中代码
    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中代码
    模拟转账
    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;
    在mysql中代码
    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())
    在pymysql中代码
    函数
      内置函数
      日期相关
    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;
    语法

    说明: paramters 只能是in 输入参数 参数名 类型

    必须有返回值

    不能加begin 和end

    returns 后面是返回值的类型 这里不加分号

    return 后面是要返回的值

    create function addfuntion(a int,b int)
    returns int return a + b;
    54asd#执行函数
    select addfuntion(1,1);
    案例

     注意:

    函数只能返回一个值

    函数不涉及数据的增删改查 就是一个通用的功能

    调用自定义的函数 与调用系统的一致 不需要call 使用select 可获得返回值

    函数中不能使用sql语句

    就像在java中不能识别sql语句一样

    数据恢复

    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
    使用mysqldump程序进行备份

    使用 mysql 进行恢复

    1.退出数据库后

    mysql -u -p < filename.sql;

    2.不用退出数据库

    2.1 创建空数据库

    2.2选择数据库

    2.3然后使用source filename; 来进行还原

    use db1;
    source /root/db1.sql
    Code
    务必保证在相同版本之间迁移
    # 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;
    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
    案例:编写过程 实现 输入一个整数type 范围 1 - 2 输出 type=1 or type=2 or type=other;
    #大体意思与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
    CASE 语句

    定义变量

    declare 变量名 类型 default 值;

    例如: declare i int default 0;

    #循环输出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
    WHILE循环
    #没有条件 需要自己定义结束语句
    语法:
    输出十次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
    LOOP循环的
    #类似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
    REPEAT循环
  • 相关阅读:
    jquery使用ajax
    Docker下使用centos无法使用systemctl怎么办
    memcache安装及解决无法远程连接的问题
    NetCore控制台程序-使用HostService和HttpClient实现简单的定时爬虫
    PHP代码审计01
    路由和交换-
    路由和交换-VLAN
    路由和交换-FTP配置
    51job招聘信息爬虫
    豆瓣电影排行250爬虫
  • 原文地址:https://www.cnblogs.com/ShenJunHui6/p/10567870.html
Copyright © 2011-2022 走看看