MySQL(2)

MySQL 注入(简单):

  我们在输入账号密码通过MySQL语句进行数据库操操作登陆的时候,除了输入正确账号密码进行正常登陆,还可以输入错误的用户密码进行登录,利用的就是MySQL -- 的注释作用

  首先创建一个userInfo表格:

mysql> select *from userInfo;
+-----+------+----------+
| nid | name | password |
+-----+------+----------+
|   1 | alex | 123      |
+-----+------+----------+
1 row in set (0.00 sec)

通过python中的pysql进行登录

import pymysql

# 创建连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='zhaoyinghan', db='db1')
# 创建游标. 负责操作
cursor = conn.cursor()
while True:
    inp_name = input('姓名:')
    inp_password = input('密码:')
    
    cammand = "select name from userInfo WHERE name = '%s' and password = '%s'"%(inp_name,inp_password)
    print('cammand = ',cammand)
    # 执行SQL,并返回收影响行数
    request = cursor.fetchone()
    print(effect_row)

    if request:
        print('登陆成功',request)
    else:
        print('密码或账号错误')
    # 执行SQL,并返回受影响行数
    # effect_row = cursor.execute("update hosts set host = '1.1.1.2' where nid > %s", (1,))

    # 执行SQL,并返回受影响行数
    # effect_row = cursor.executemany("insert into hosts(host,color_id)values(%s,%s)", [("1.1.1.11",1),("1.1.1.11",2)])

    # 提交,不然无法保存新建或者修改的数据
    conn.commit()

# 关闭游标
cursor.close()
# 关闭连接
conn.close()

>>>
  姓名:alex
  密码:123
  cammand = select name from userInfo WHERE name = 'alex' and password = '123'
  1
  登陆成功 ('alex',)

  # 输入正确用户名 密码 登录成功


  姓名:alex' -- dfadf
  密码:asdf
  cammand = select name from userInfo WHERE name = 'alex' -- dfadf' and password = 'asdf'
  1
  登陆成功 ('alex',)

  # 输入错误用户名密码 也登录成功,这是因为 在MySQL命令语句中, -- 代表着注释之后的内容 ,执行的"cammand"命令中 只是执行了 select name from userInfo WHERE name = 'alex' 语句,
   所以可以登录成功,这就是SQL注入,以后也是需要注意的地方,而pymysql中 提封装了可输入参数的MySQL函数-> execute(query,args =None)我们只需要更改一下用到的execute函数就可以避免了
  effect_row = cursor.execute("select name from userInfo WHERE name = '%s' and password = '%s'",(inp_name,inp_password))   这样我们再次输入 ' -- '就不会出现上述情况了

视图:

  视图是一个虚拟表(非真实存在),其本质是【根据SQL语句获取动态的数据集,并为其命名】,用户使用时只需使用【名称】即可获取结果集,并可以将其当作表来使用。

临时表搜索:

mysql> select * from Person_1;
+----+-------+-----+--------+
| id | name  | age | color  |
+----+-------+-----+--------+
|  1 | tom   |  11 | white  |
|  2 | jerry |  12 | yellow |
|  3 | jack  |  14 | white  |
|  4 | rose  |  14 | blue   |
|  5 | herry |  21 | red    |
+----+-------+-----+--------+

mysql> select * from(select * from Person_1 where id < 4) as new_P where new_P.color = 'white';
    # 通过()将筛选条件扩阔入,然后从筛选出来的结果中继续筛选
+----+------+-----+-------+ | id | name | age | color | +----+------+-----+-------+ | 1 | tom | 11 | white | | 3 | jack | 14 | white | +----+------+-----+-------+ 2 rows in set (0.00 sec)

创建视图:

  CREATE VIEW  视图名称 AS 条件语句

  当需要在筛选后的表格内做重复操作的时候,我们可以通过视图将所筛选的表进行保存,然后通过视图继续进行重复性的操作

>>>
mysql> create view new_P as select* from Person_1 where id <4; # 创建名为new_P的视图
Query OK, 0 rows affected (0.01 sec)
mysql
> select *from new_P; # 显示视图 +----+-------+-----+--------+ | id | name | age | color | +----+-------+-----+--------+ | 1 | tom | 11 | white | | 2 | jerry | 12 | yellow | | 3 | jack | 14 | white | +----+-------+-----+--------+ 3 rows in set (0.00 sec)

删除视图:

  DROP VIEW 视图名称 ,和删除表格一个格式
drop view new_P;

修改视图:

  ALTER VIEW 视图名称 AS 条件语句

mysql> alter view new_P as select *from new_P where id<3; #更改时,不可根据自身进行更改
ERROR 1146 (42S02): Table 'db1.new_p' doesn't exist
mysql> 
mysql> alter view new_P as select *from Person_1 where id<3; # 进行更改数据
Query OK, 0 rows affected (0.00 sec)

mysql> select *from new_P;
+----+-------+-----+--------+
| id | name  | age | color  |
+----+-------+-----+--------+
|  1 | tom   |  11 | white  |
|  2 | jerry |  12 | yellow |
+----+-------+-----+--------+
2 rows in set (0.00 sec)

存储过程:

  存储过程是一个SQL语句集合,当主动去调用存储过程时,其中内部的SQL语句会按照逻辑执行(类似于函数)。

创建:

  CREATE PROCEDURE 名称(参数) START 存储过程 END

 

mysql> delimiter //         # sql语句中是以;为结束语句,但创建procedure时,也是会有;为了避免提前结束,更改结束语句为 //
mysql> drop procedure if exists p_1//   # 如果procedure p_1存在的话,就删除,防止procedure 命名冲突
Query OK, 0 rows affected (0.00 sec)

mysql> create procedure p_1() #创建procedure p_1 ,括号内的是参数
    -> begin #开始
    -> select *from Person_1;
    -> end// #结束,用//来告知系统语句执行结束位置
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;  # 将结束符号更改回;
mysql> call p_1;  # 调用procedure p_1
+----+-------+-----+--------+
| id | name  | age | color  |
+----+-------+-----+--------+
|  1 | tom   |  11 | white  |
|  2 | jerry |  12 | yellow |
|  3 | jack  |  14 | white  |
|  4 | rose  |  14 | blue   |
|  5 | herry |  21 | red    |
+----+-------+-----+--------+
5 rows in set (0.01 sec)

Query OK, 0 rows affected (0.01 sec)

 

参数:

  in 参数名称 参数类型      - 传入参数

  inout 参数名称 参数类型   - 传入、返回参数

  out 参数名称 参数类型   - 返回参数

 


delimiter // DROP PROCEDURE IF EXISTS p_2// CREATE PROCEDURE p_2(IN i INT , INOUT j INT , OUT k INT) # 创建带参数的 PROCEDURE IF i = 1 THEN SET j = 100 + j ; SET k = 100 + i ; ELSE SET j = 200 + j ; SET k = 200 + i ; END IF ; END// delimiter ; #调用 SET @j = 2; SET @k = 0; CALL p_2(1 ,@j ,@k); SELECT @j ,@k mysql> select @j,@k; +------+------+ | @j | @k | +------+------+ | 102 | 101 | +------+------+ 1 row in set (0.00 sec)

 

通过pymysql进行操作:

# 创建PROCEDURE 命名为p_3
delimiter //
DROP PROCEDURE
IF EXISTS p_3//

CREATE PROCEDURE p_3(IN i INT , INOUT j INT , OUT k INT)
IF i = 1 THEN
    SET j = 100 + j ;
    SET k = 100 + i ;
    select *from Person_1;
ELSE

    SET j = 200 + j ;
    SET k = 200 + i ;
END IF ;
END//
delimiter ;


import pymysql

# 创建连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='zhaoyinghan', db='db1')
# 创建游标. 负责操作
cursor = conn.cursor()
# 执行存储过程 传参数的时候,只有in和inout才会传入进去,out的就直接忽略了
row = cursor.callproc('p_3',(1,1,1))
# 当执行过程中有查询语句的时候,可以在cursor.executer 之前获取查询结果(必须在cursor.executer之前)
result = cursor.fetchall()
# 执行 获取 返回值
effect_row = cursor.execute('select @_p_3_0, @_p_3_1, @_p_3_2')
# 获取存储过程的返回值
sel = cursor.fetchall()
print(result,sel)
# 关闭游标
cursor.close()
# 关闭连接
conn.close()

>>>
    ((1, 'tom', 11, 'white'), (2, 'jerry', 12, 'yellow'), (3, 'jack', 14, 'white'), (4, 'rose', 14, 'blue'), (5, 'herry', 21, 'red')) 
   ((1, 101, 101),) # 执行后返回的结果

触发器:

  对某个表进行【增/删/改】操作的前后如果希望触发某个特定的行为时,可以使用触发器,触发器用于定制用户对表的行进行【增/删/改】前后的行为。

 

# 插入前
CREATE TRIGGER trigger名称 BEFORE INSERT ON 触发的表 FOR EACH ROW
BEGIN
    ...
END

# 插入后
CREATE TRIGGER trigger名称 AFTER INSERT ON 触发的表 FOR EACH ROW
BEGIN
    ...
END

# 删除前
CREATE TRIGGER trigger名称 BEFORE DELETE ON 触发的表 FOR EACH ROW
BEGIN
    ...
END

# 删除后
CREATE TRIGGER trigger名称 AFTER DELETE ON 触发的表 FOR EACH ROW
BEGIN
    ...
END

# 更新前
CREATE TRIGGER trigger名称 BEFORE UPDATE ON 触发的表 FOR EACH ROW
BEGIN
    ...
END

# 更新后
CREATE TRIGGER trigger名称 AFTER UPDATE ON 触发的表 FOR EACH ROW
BEGIN
    ...
END
触发器创建基本语法

 

创建触发器:

以 insert 和 before为例:
delimiter // drop TRIGGER if EXISTS t_1// create trigger t_1 before insert on Person_1 fro each row
#create Trigger t_1 创建触发器命名为t_1 #before insert on Person_1 在对表Person_1进行insert操作的时候 #for each row 每一行insert 都触发,比如在同一语句中添加了两行值 insert into Person_1(xx,xx,xx) values(xx,xx,xx)(xx,xx,xx) ,那么添加的所有值都会影响到 BEGIN INSERT INTO userInfo(name,password) VALUES(NEW.name,NEW.color)); #在userInfo表格中添加新添加到Person_1中的 name 和password的值,其中NEW代表着Person_1新插入的值 END// delimiter ; mysql> select *from Person_1; +----+-------+-----+--------+ | id | name | age | color | +----+-------+-----+--------+ | 1 | tom | 11 | white | | 2 | jerry | 12 | yellow | | 3 | jack | 14 | white | | 4 | rose | 14 | blue | | 5 | herry | 21 | red | +----+-------+-----+--------+ 5 rows in set (0.00 sec) mysql> select *from userInfo; +-----+------+----------+ | nid | name | password | +-----+------+----------+ | 1 | alex | 123 | +-----+------+----------+ 1 row in set (0.00 sec) #对Person_1执行insert mysql> insert into Person_1(name,age,color) values('tony',32,'cyan'); Query OK, 1 row affected (0.00 sec) mysql> select *from Person_1; +----+-------+-----+--------+ | id | name | age | color | +----+-------+-----+--------+ | 1 | tom | 11 | white | | 2 | jerry | 12 | yellow | | 3 | jack | 14 | white | | 4 | rose | 14 | blue | | 5 | herry | 21 | red | | 6 | tony | 32 | cyan | +----+-------+-----+--------+ 6 rows in set (0.00 sec) mysql> select *from userInfo; +-----+------+----------+ | nid | name | password | +-----+------+----------+ | 1 | alex | 123 | | 2 | tony | cyan | +-----+------+----------+ 2 rows in set (0.00 sec)

     当然,触发器中有befroe也会有after,而在insert 中我们是用NEW关键字来获取新插入Person_1中的数据。在delect数据的时候,因为删除的数据是旧的,所以我们就用old来获取删除的数据。

以删除数据为例:
delimiter // drop TRIGGER if EXISTS t_2// CREATE TRIGGER t_2 BEFORE DELETE on Person_1 FOR EACH ROW BEGIN DELETE FROM userInfo WHERE NAME = old.name; END// delimiter ; # 执行Person_1 删除语句 mysql> delete from Person_1 where name = 'tony'; Query OK, 1 row affected (0.00 sec) mysql> select *from userInfo; +-----+------+----------+ | nid | name | password | +-----+------+----------+ | 1 | alex | 123 | +-----+------+----------+ 1 row in set (0.00 sec) mysql> select *from Person_1; +----+-------+-----+--------+ | id | name | age | color | +----+-------+-----+--------+ | 1 | tom | 11 | white | | 2 | jerry | 12 | yellow | | 3 | jack | 14 | white | | 4 | rose | 14 | blue | | 5 | herry | 21 | red | +----+-------+-----+--------+ 5 rows in set (0.00 sec)

 

删除触发器:

drop trigger 触发器名称
mysql> drop TRIGGER if EXISTS t_2;
Query OK, 0 rows affected (0.01 sec)

MySQL 函数:

  同样的,在MYSQL中也是有内置的相关函数,上边提到执行Procedure的时候用call 而执行函数的时候用select。

  官网内置函数

查看字符串长度:char_length(str)

mysql> select char_length('alex');
+---------------------+
| char_length('alex') |
+---------------------+
|                   4 |
+---------------------+
1 row in set (0.00 sec)

  拼接字符串:concat(str_1,str_2) 如有任何一个参数为NULL,则返回NULL

mysql> select concat('My','SQL');
+--------------------+
| concat('My','SQL') |
+--------------------+
| MySQL              |
+--------------------+
1 row in set (0.00 sec)
# 如有任何一个参数为NULL ,则返回值为 NULL。
mysql> select concat('My',Null);
+-------------------+
| concat('My',Null) |
+-------------------+
| NULL              |
+-------------------+
1 row in set (0.00 sec)
字符串拼接(自定义连接符): concat_ws(separator,str1,str2)
mysql> select concat_ws('_','alex','22','red');
+----------------------------------+
| concat_ws('_','alex','22','red') |
+----------------------------------+
| alex_22_red                      |
+----------------------------------+
1 row in set (0.00 sec)
其他:
CONV(N,from_base,to_base)
        进制转换
        例如:
            SELECT CONV('a',16,2); 表示将 a 由16进制转换为2进制字符串表示

    FORMAT(X,D)
        将数字X 的格式写为'#,###,###.##',以四舍五入的方式保留小数点后 D 位, 并将结果以字符串的形式返回。若  D 为 0, 则返回结果不带有小数点,或不含小数部分。
        例如:
            SELECT FORMAT(12332.1,4); 结果为: '12,332.1000'
    INSERT(str,pos,len,newstr)
        在str的指定位置插入字符串
            pos:要替换位置其实位置
            len:替换的长度
            newstr:新字符串
        特别的:
            如果pos超过原字符串长度,则返回原字符串
            如果len超过原字符串长度,则由新字符串完全替换
    INSTR(str,substr)
        返回字符串 str 中子字符串的第一个出现位置。
    LEFT(str,len)
        返回字符串str 从开始的len位置的子序列字符。
    LOWER(str)
        变小写
    UPPER(str)
        变大写
    LTRIM(str)
        返回字符串 str ,其引导空格字符被删除。
    RTRIM(str)
        返回字符串 str ,结尾空格字符被删去。
    SUBSTRING(str,pos,len)
        获取字符串子序列

    LOCATE(substr,str,pos)
        获取子序列索引位置

    REPEAT(str,count)
        返回一个由重复的字符串str 组成的字符串,字符串str的数目等于count 。
        若 count <= 0,则返回一个空字符串。
        若str 或 count 为 NULL,则返回 NULL 。
    REPLACE(str,from_str,to_str)
        返回字符串str 以及所有被字符串to_str替代的字符串from_str 。
    REVERSE(str)
        返回字符串 str ,顺序和字符顺序相反。
    RIGHT(str,len)
        从字符串str 开始,返回从后边开始len个字符组成的子序列

    SPACE(N)
        返回一个由N空格组成的字符串。

    SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len)
        不带有len 参数的格式从字符串str返回一个子字符串,起始于位置 pos。带有len参数的格式从字符串str返回一个长度同len字符相同的子字符串,起始于位置 pos。 使用 FROM的格式为标准 SQL 语法。也可能对pos使用一个负值。假若这样,则子字符串的位置起始于字符串结尾的pos 字符,而不是字符串的开头位置。在以下格式的函数中可以对pos 使用一个负值。

        mysql> SELECT SUBSTRING('Quadratically',5);
            -> 'ratically'

        mysql> SELECT SUBSTRING('foobarbar' FROM 4);
            -> 'barbar'

        mysql> SELECT SUBSTRING('Quadratically',5,6);
            -> 'ratica'

        mysql> SELECT SUBSTRING('Sakila', -3);
            -> 'ila'

        mysql> SELECT SUBSTRING('Sakila', -5, 3);
            -> 'aki'

        mysql> SELECT SUBSTRING('Sakila' FROM -4 FOR 2);
            -> 'ki'

    TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str) TRIM(remstr FROM] str)
        返回字符串 str , 其中所有remstr 前缀和/或后缀都已被删除。若分类符BOTH、LEADIN或TRAILING中没有一个是给定的,则假设为BOTH 。 remstr 为可选项,在未指定情况下,可删除空格。

        mysql> SELECT TRIM('  bar   ');
                -> 'bar'

        mysql> SELECT TRIM(LEADING 'x' FROM 'xxxbarxxx');
                -> 'barxxx'

        mysql> SELECT TRIM(BOTH 'x' FROM 'xxxbarxxx');
                -> 'bar'

        mysql> SELECT TRIM(TRAILING 'xyz' FROM 'barxxyz');
                -> 'barx'

自定义函数:

创建函数:

delimiter //
drop function IF EXISTS f1//
create function f1(
    i1 int,
    i2 int)
returns int # 告知系统有一个int类型的返回值
BEGIN #开始
    declare num int;  # 需要注意的是函数体内,是不可以有查询语句,否则会报错。
    set num = i1 + i2;
    return(num);
END // #结束
delimiter ;

# 调用函数
mysql> select f1(1,2);
+---------+
| f1(1,2) |
+---------+
|       3 |
+---------+
1 row in set (0.00 sec)

# 这里需要注意的是,函数和存储过程的区别是 调用Procedure用call 而 函数是select 并且 函数可以和表格操作仪一块使用:
mysql> select f1(1,id),id,name from Person_1;
+----------+----+-------+
| f1(1,id) | id | name  |
+----------+----+-------+
|        2 |  1 | tom   |
|        3 |  2 | jerry |
|        4 |  3 | jack  |
|        5 |  4 | rose  |
|        6 |  5 | herry |
+----------+----+-------+
5 rows in set (0.00 sec)

删除函数:

drop fuction 函数名

mysql> drop function f1;
Query OK, 0 rows affected (0.00 sec)

 

事物操作:

  事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,即可回滚到原来的状态,从而保证数据库数据完整性。(回滚操作)

delimiter //
drop PROCEDURE if EXISTS p1//
CREATE PROCEDURE p1(
    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 Person_1 set name = 'lala' where id = 3;
    UPDATE Person_1 set age = 33 where id = 5;
COMMIT ; # 提交

-- SUCCESS 
   SET p_return_code = 0 ;
END//
delimiter ;

# 执行
mysql> drop function f1;
Query OK, 0 rows affected (0.00 sec)

mysql> set @i = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> call p1(@i);
Query OK, 0 rows affected (0.00 sec)

mysql> select @i;
+------+
| @i   |
+------+
|    0 |
+------+
1 row in set (0.00 sec)

需要了解到的是 在pymsql中 是默认支持回滚操作。

 动态执行MySQL语句:

创建 Procedure 动态执行
delimiter \\
DROP PROCEDURE IF EXISTS proc_sql \\
CREATE PROCEDURE proc_sql (in sql_str varchar(125),in num )
BEGIN
    declare p1 int;
    set p1 = 11;
    set @p1 = p1;

    PREPARE prod FROM 'select * from tb2 where nid > ?';  #预编译
    EXECUTE prod USING @p1;    #将MySQL语句中的占位符 " ? "替换成@p1
    DEALLOCATE prepare prod;   #删除语句 prod

END\\
delimiter ;

动态执行SQL:

mysql
> call proc_sql('select *from Person_1 where id > ?',2); +----+-------+-----+-------+ | id | name | age | color | +----+-------+-----+-------+ | 3 | lala | 14 | white | | 4 | rose | 14 | blue | | 5 | herry | 33 | red | +----+-------+-----+-------+ 3 rows in set (0.00 sec) Query OK, 0 rows affected (0.00 sec) #pymysql 中执行: import mysql # 创建连接 conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='zhaoyinghan', db='db1') # 创建游标. 负责操作 cursor = conn.cursor() # 输入带有占位符的Mysql语句与参数 row = cursor.callproc('proc_sql',('select * from Person_1 where id > ?',1)) # 当执行过程中有查询的时候,可以在cursor.executer 之前 获取一下 查询结果(必须在cursor.executer之前) result = cursor.fetchall() print(result) # 关闭游标 cursor.close() # 关闭连接 conn.close() >>> ((2, 'jerry', 12, 'yellow'), (3, 'lala', 14, 'white'), (4, 'rose', 14, 'blue'), (5, 'herry', 33, 'red'))

 

 

posted @ 2017-07-29 17:47  LeeeetMe  阅读(146)  评论(0编辑  收藏  举报