Python学习—数据库篇之SQL补充
Posted cdcx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python学习—数据库篇之SQL补充相关的知识,希望对你有一定的参考价值。
一、SQL注入问题
在使用pymysql进行信息查询时,推荐使用传参的方式,禁止使用字符串拼接方式,因为字符串拼接往往会带来sql注入的问题
1 # -*- coding:utf-8 -*- 2 # author: cdc 3 # date: 2019/3/18 4 5 import pymysql 6 7 conn = pymysql.connect(host=‘127.0.0.1‘,port=3306,user=‘root‘,password=‘cdc19951216‘,db=‘test‘,charset=‘utf8‘) 8 9 cursor = conn.cursor() 10 11 # 传参方式查询数据 12 cursor.execute(‘select * from user_info where name=%s and password=%s‘,(‘cdc‘,‘123456‘,)) 13 res = cursor.fetchone() 14 print(res) 15 16 # 执行结果 >>>> (1, ‘cdc‘, ‘123456‘)
1 # -*- coding:utf-8 -*- 2 # author: cdc 3 # date: 2019/3/18 4 5 import pymysql 6 7 conn = pymysql.connect(host=‘127.0.0.1‘,port=3306,user=‘root‘,password=‘cdc19951216‘,db=‘test‘,charset=‘utf8‘) 8 9 cursor = conn.cursor() 10 11 # 字符串拼接方式查询 12 sql = ‘select * from user_info where name="%s" and password="%s"‘ 13 inp = (‘cdc‘,‘123456‘) 14 sql = sql % inp 15 cursor.execute(sql) 16 res = cursor.fetchone() 17 print(res) 18 19 # 执行结果 >>>>> (1, ‘cdc‘, ‘123456‘)
乍一看,两种方式都可以执行成功,但是只要对字符串拼接的方法稍微改动一下就能很明显的看出此类方式的弊端
# -*- coding:utf-8 -*- # author: cdc # date: 2019/3/18 import pymysql conn = pymysql.connect(host=‘127.0.0.1‘,port=3306,user=‘root‘,password=‘cdc19951216‘,db=‘test‘,charset=‘utf8‘) cursor = conn.cursor() sql = ‘select * from user_info where name="%s" and password="%s"‘ inp = (‘cdc" and 1=1 -- ‘,‘123456‘) sql = sql % inp cursor.execute(sql) res = cursor.fetchone() print(res) # 执行结果 >>>>> (1, ‘cdc‘, ‘123456‘)
按理来说,数据库中并未满足条件的数据,但是还是可以执行成功,这是因为将字符串‘cdc" and 1=1 -- ‘替换掉对应的占位符后会将sql语句变为:
1 select * from user_info where name="cdc" and 1=1 -- " and password="%s"
此时后面password的条件已经被注释掉了,真正执行的判断条件是name=‘cdc‘和1=1,这个条件恒为true,因此无论如何都可以从数据库中查询到信息,因此使用字符串拼接的方式进行查询风险很大。
二、视图
视图是一个虚拟表(非真实存在),其本质是【根据SQL语句获取动态的数据集,并为其命名】,用户使用时只需使用【名称】即可获取结果集,并可以将其当作表来使用。(实例化来说,可能某个需求需要重复的对某张表中的某些数据进行反复操作,每次重写重复的sql与是十分没有必要的,可以先将要操作的数据提取出来,作为一张临时的表)
1、创建视图
1 --格式:CREATE VIEW 视图名称 AS SQL语句 2 3 CREATE VIEW temp1 AS SELECT no,name from tb3 where tb3.part_no>2
2、删除视图
1 --格式:DROP VIEW 视图名称 2 3 DROP VIEW temp1
3、修改视图
1 -- 格式:ALTER VIEW 视图名称 AS SQL语句 2 3 ALTER VIEW temp1 AS SELECT no,name,part_no FROM tb3 WHERE part_no!=1
4、使用视图
使用视图时,将其当作表进行操作即可,由于视图是虚拟表,所以无法使用其对真实表进行创建、更新和删除操作,仅能做查询用。
1 select * from v1
三、存储过程
存储过程是一个SQL语句集合,当主动去调用存储过程时,其中内部的SQL语句会按照逻辑执行。(进一步提升了视图的简洁性和功能,使用方式类似于python中函数调用)
1、创建存储过程
1 -- 创建存储过程 2 3 delimiter // 4 create procedure p1() 5 BEGIN 6 select * from tb3; 7 END// 8 delimiter ; 9 10 -- delimiter的作用是修改sql语句执行结束的判断标志,即若按照原来的方式,每当遇到 ; 则sql语句输入结束并运行,这样后面的END就不会生效,现先将执行结束的标志改为 // ,sql语句遇到//时才表示结束
1 # *************** 终端调用 **************** 2 call p1() 3 4 # ************* pymysql调用 ***************** 5 import pymysql 6 # 创建连接 7 conn = pymysql.connect(host=‘127.0.0.1‘, port=3306, user=‘root‘, passwd=‘cdc19951216‘, db=‘test‘,charset=‘utf8‘) 8 # 创建游标 9 cursor = conn.cursor() 10 cursor.callproc(‘p1‘) 11 12 result = cursor.fetchone() 13 print(result) 14 15 # 关闭游标 16 cursor.close() 17 # 关闭连接 18 conn.close()
对于存储过程,可以接收参数,其参数有三类:
- in 仅用于传入参数用
- out 仅用于返回值用
- inout 既可以传入又可以当作返回值
1 -- 创建存储过程 2 delimiter 3 create procedure p1( 4 in i1 int, -- 可以理解为i1为整型参数,且只提供输入值的功能,使用前必须赋值 5 in i2 int, 6 inout i3 int, -- 可以理解为i3为整型参数,既要提供输入值又要提供返回值的功能,使用前必须赋值 7 out r1 int -- 可以理解为r1为整型参数,且只提供返回值的功能,开始时不必赋值,如果有值也会被后期覆盖掉 8 ) 9 BEGIN 10 DECLARE temp1 int; -- 定义一个整型变量temp1 11 DECLARE temp2 int default 0; -- 定义一个整型变量temp2,初始值为0 12 13 set temp1 = 1; -- 赋值 14 15 set r1 = i1 + i2 + temp1 + temp2; -- r1 = 1+2+1+0 16 17 set i3 = i3 + 100; -- i3=4+100 18 19 end20 delimiter ; 21 22 -- 执行存储过程 23 set @t1 =4; 24 set @t2 = 0; 25 CALL p1 (1, 2 ,@t1, @t2); 26 SELECT @t1,@t2; -- 最后返回的是i3和r1的值
To be continue... ...