mysql数据库(day5)-视图,触发器,存储过程

视图,触发器

1. 视图(以后开发中不常用,不推荐使用)
        100个SQL:
            88: v1
            
            select .. from v1
            select asd from v1
        某个查询语句设置别名,日后方便使用
            物理表数据变化视图跟着变,但是视图不支持insert
        - 创建
            create view 视图名称 as  SQL
            
            PS: 虚拟
        - 修改
            alter view 视图名称 as  SQL
            
        - 删除
            drop view 视图名称;
        
    2. 触发器(不推荐使用)类似装饰器,在语句之前之后做点什么
        
        当对某张表做:增删改操作时,可以使用触发器自定义关联行为
        
        insert into tb (....)
        
        -- delimiter //
        -- create trigger t1 BEFORE INSERT on student for EACH ROW
        -- BEGIN
        --     INSERT into teacher(tname) values(NEW.sname);
        --     INSERT into teacher(tname) values(NEW.sname);
        --     INSERT into teacher(tname) values(NEW.sname);
        --     INSERT into teacher(tname) values(NEW.sname);
        -- END //
        -- delimiter ;
        -- 

        -- insert into student(gender,class_id,sname) values('',1,'陈涛'),('',1,'张根');

        -- NEW,代指新数据
        -- OLD,代指老数据
View Code

 参考博客:

http://www.cnblogs.com/wupeiqi/articles/5713323.html

 

函数:

3. 函数   函数是保存在数据库中的,在python中是看不到
        def f1(a1,a2):
            return a1 + a2
            
        f1()
        bin()
        
        内置函数:
            执行函数 select CURDATE();
            
            blog
            id       title            ctime
             1        asdf        2019-11
             2        asdf        2019-11
             3        asdf        2019-10
             4        asdf        2019-10
             
             
            select ctime,count(1) from blog group ctime
            
            select DATE_FORMAT(ctime, "%Y-%m"),count(1) from blog group DATE_FORMAT(ctime, "%Y-%m")
            2019-11   2
            2019-10   2
            
            
        自定义函数(有返回值):
            
            delimiter \\                 --更改终止符
                create function f1(
                    i1 int,               --定义的是整型,传进去只能是整型
                    i2 int)
                returns int
                BEGIN   --函数体,里面不能写select * from tb,直接就报错了,存储过程可以写
                    declare num int default 0;
                    set num = i1 + i2;
                    return(num);
                END \\
            delimiter ;
            
            SELECT f1(1,100);  数据库函数的调用,函数是有返回值的
            
View Code

 

存储过程

    概念是什么:保存在MySQL上的一个别名 => 一坨SQL语句
    跟视图特别像,视图当作一张表来调用,存储过程里面直接写名字,视图不能进行插入进行更改,
    视图的结果集可以是多张表,存储过程相当于好多的语句的合集,存储过程想干什么干什么,不受限制   

    好的作用:
    1:用于替代程序员写SQL语句(有了存储过程,你就可以不用写了)
    2:网络传输的时个用存储过程省流量



  

    4. 存储过程(用的不多,但是你要知道从5.5才有存储过程)
           概念是什么:保存在MySQL上的一个别名 => 一坨SQL语句
                    跟视图特别像,视图当作一张表来调用,存储过程里面直接写名字,视图不能进行插入进行更改,
                    视图的结果集可以是多张表,存储过程相当于好多的语句的合集,存储过程想干什么干什么,不受限制
            
        好的作用:
            1:用于替代程序员写SQL语句(有了存储过程,你就可以不用写了)
            2:网络传输的时个用存储过程省流量
        
        方式一:
            MySQL: 存储过程
            程序:调用存储过程
        方式二:
            MySQL:。。
            程序:SQL语句
        方式三:
            MySQL:。。
            程序:类和对象(SQL语句)
            
            
        1. 创建一个简单的存储过程
        delimiter //
            create procedure p1()
            BEGIN
                select * from student;
                INSERT into teacher(tname) values("ct");
            END
        delimiter ;
            call p1() 执行存储过程
            cursor.callproc('p1') 调用存储过程
        
        2. 传参数(in,out,inout)有三个关键字,in 只能往里面传不能返; out,从外面传不进去只能返,inout,能传能拿出来
            delimiter //
            create procedure p2(
                in n1 int,   #in 在存储过程里面用
                in n2 int
            )
            BEGIN
                
                select * from student where sid > n1;
            END //
            delimiter ;
            
            call p2(12,2)    你写了几个参数,调用的时候必须写参数,而且即使用不到你也要写上
            cursor.callproc('p2',(12,2))
            
        3. 参数 out(存储过程没有return)
            delimiter //
            create procedure p3(
                in n1 int,
                inout n2 int  #
            )
            BEGIN
                set n2 = 123123;
                select * from student where sid > n1;
            END //
            delimiter ;
            
            set @v1 = 10;
            call p2(12,@v1)
            select @v1;
            
            set @_p3_0 = 12
            ser @_p3_1 = 2
            call p3(@_p3_0,@_p3_1)
            select @_p3_0,@_p3_1

            
            
            
            cursor.callproc('p3',(12,2))
            r1 = cursor.fetchall()
            print(r1)


            cursor.execute('select @_p3_0,@_p3_1')
            r2 = cursor.fetchall()
            print(r2)

            =======> 特殊
                    a. 可传参: in   out   inout
                    b. pymysql
                        
                            cursor.callproc('p3',(12,2))
                            r1 = cursor.fetchall()
                            print(r1)

                            cursor.execute('select @_p3_0,@_p3_1')  ----想拿返回值必须再执行一下
                            r2 = cursor.fetchall()
                            print(r2)
                                        
        为什么有结果集又有out伪造的返回值?
        
        
            delimiter //
            create procedure p3(
                in n1 int,
                out n2 int  用于标识存储过程的执行结果  比如1,2,代表不同的结果,如1是成功,2代表执行错了
            )
            BEGIN
                insert into vv(..)
                insert into vv(..)
                insert into vv(..)
                insert into vv(..)
                insert into vv(..)
                insert into vv(..)
            END //
            delimiter ;
View Code

pymysql引用存储过程的代码

import pymysql

conn = pymysql.connect(host="localhost",user='root',password='',database="db666",charset='utf8')
cursor = conn.cursor()
cursor.callproc('p3',(12,2))
r1 = cursor.fetchall()
print(r1)

cursor.execute('select @_p5_0')
r2 = cursor.fetchall()
print(r2)
cursor.close()
conn.close()

"""
set @_p3_0 = 12
ser @_p3_1 = 2
call p3(@_p3_0,@_p3_1)
select @_p3_0,@_p3_1
"""
View Code

事物和游标(属于存储过程)

4. 事务
        
            
            delimiter //
            create procedure p4(
                out status int
            )
            BEGIN
                1. 声明如果出现异常则执行{
                    set status = 1;
                    rollback;
                }
                   
                开始事务
                    -- 由秦兵账户减去100
                    -- 方少伟账户加90
                    -- 张根账户加10
                    commit;
                结束
                
                set status = 2;
                
                
            END //
            delimiter ;
            
            ===============================
            delimiter \\
            create PROCEDURE p5(
                OUT p_return_code tinyint
            )
            BEGIN 
              DECLARE exit handler for sqlexception 
              BEGIN 
                -- ERROR 
                set p_return_code = 1; 
                rollback; 
              END; 
             
              START TRANSACTION; 
                DELETE from tb1;
                insert into tb2(name)values('seven');
              COMMIT; 
             
              -- SUCCESS 
              set p_return_code = 2; 
             
              END\\
            delimiter ;

        
        5. 游标(能不用游标就不用游标,性能不高)
        
            delimiter //
            create procedure p6()
            begin 
                declare row_id int; -- 自定义变量1  
                declare row_num int; -- 自定义变量2 
                declare done INT DEFAULT FALSE;
                declare temp int;
                
                declare my_cursor CURSOR FOR select id,num from A;
                declare CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
                
                
                
                open my_cursor;
                    xxoo: LOOP
                        fetch my_cursor into row_id,row_num;
                        if done then 
                            leave xxoo;
                        END IF;
                        set temp = row_id + row_num;
                        insert into B(number) values(temp);
                    end loop xxoo;
                close my_cursor;
                
                
            end  //
            delimter ;
View Code

 

动态sql执行(放sql注入在数据库级别)

  目前有两种方法防止sql注入(pymsql,数据库)

 动态执行SQL(防SQL注入)
            伪代码
            delimiter //
            create procedure p7(
                in tpl varchar(255),
                in arg int
            )
            begin 
                1. 预检测某个东西 SQL语句合法性
                2. SQL =格式化 tpl + arg 
                3. 执行SQL语句
                
                set @xo = arg; 接下来执行的变量必须是session级别的变量,所以就有了这个设置
                PREPARE xxx FROM 'select * from student where sid > ?'; 这个?是占位符
                EXECUTE xxx USING @xo;
                DEALLOCATE prepare prod; 
            end  //
            delimter ;
        
        
            
            call p7("select * from tb where id > ?",9)
        
            ===> 
    
            delimiter \\
            CREATE PROCEDURE p8 (
                in nid int
            )
            BEGIN
                set @nid = nid;
                PREPARE prod FROM 'select * from student where sid > ?';
                EXECUTE prod USING @nid;
                DEALLOCATE prepare prod; 
            END\\
            delimiter ;
View Code

对性能要求不高可以用函数,索引能加速查找,但是有函数就索引无效了。 

 

posted @ 2018-01-12 14:21  wanchenxi  阅读(134)  评论(0编辑  收藏  举报