1、查询流程
- 创建数据库连接conn=connect(参数)
- 创建游标对象 cursor = conn.cursor()
- sql语句查询执行 count = cursor.execute(查询sql语句),返回值是查到的记录数
- 获取查询到的结果集result = couserfetchall()/result = couserfetchmany(参数)/result = couserfetchone()
- 关闭游标,cursor.close()
- 关闭连接对象conn.close()
2、增删改流程
- 创建数据库连接conn=connect(参数)
- 创建游标对象 cursor = conn.cursor()
- sql语句增删改执行 count = cursor.execute(查询sql语句),返回值是查到的记录数
- 连接对象提交 conn.commit()
- 关闭游标,cursor.close()
- 关闭连接对象conn.close()
注:只有当执行到commit时数据库内容才会更改,没有执行到时数据库的AUTO_INCREMENT自动增加,rollback 回滚到事务前
3、sql注入
3.1、什么是sql注入
假如 我python代码中使用如下字符串格式化后的sql语句就会造成sql注入:
name = input("请输入要查询的商品名:")
sql = '''select * from goods where name ='%s' ;'''%(name,) #当用户输入 ' or 1=1 or ' 将会查出所有信息
count = cursor.execute(sql)
result = cursor.fetchall()
print("---------->%s<--------------------\n"%sql)
print(result)
当用户输入’ or 1=1 or '时 将把sql语句解析成如下内容:
select * from goods where name =' ' or 1=1 or ' ' ;
这样当我执行cursor.execute(sql)就表示成查询所有信息,而我本意是按照用户输入的名字查询。而不是查询所有信息。这样就容易造成信息泄露
3.2、防范sql泄露
sql语句的参数化,可以有效防止sql注入,如下:
name = input("请输入要查询的商品名:")
param = list()
param.append(name)
sql = '''select * from goods where name =%s ;'''
print("---------->%s<--------------------\n"%sql)
cursor.execute(sql,param[0]) #可以防止sql注入,在写sql时不要自己拼接sql语句
result = cursor.fetchall()
此处不同于python的字符串格式化,全部使用%s占位
4、示例代码:
import pymysql
class JD(object):
'''JD类'''
def __init__(self):
'''初始化'''
self.switch = 0
try:
self.conn = pymysql.connect(host = 'localhost',port = 3306,database = 'jingdong',user = 'root',password = '123456',charset = 'utf8')
self.cursor = self.conn.cursor()
except Exception as mysql_err:
self.switch = 0
print("数据库连接失败\n")
else:
self.switch = 1
def __del__(self):
if self.switch == 1:
self.cursor.close()
self.conn.close()
print("连接已关闭")
else:
pass
def execute_sql(self,sql):
'''执行sql语句'''
count = self.cursor.execute(sql)
result = self.cursor.fetchall()
for temp in result:
print(temp)
def show_all(self):
'''显示所有商品信息'''
sql = 'select id as 序号,name as 商品名,cate_id as 商品类别,brand_id as 品牌,price as 价格 from goods'
self.execute_sql(sql)
def show_cate(self):
'''显示所有商品信息'''
sql = 'select id as 序号 ,name as 商品类别 from goods_cate'
self.execute_sql(sql)
def show_brand(self):
'''显示所有商品信息'''
sql = 'select id as 序号 ,name as 商品类别 from goods_brand'
self.execute_sql(sql)
def get_info_by_name_no(self):
'''不能防范sql注入'''
name = input("请输入要查询的商品名:")
sql = '''select * from goods where name ='%s' ;'''%(name,) #当用户输入' or 1=1 or ' 将会查出所有信息
print("---------->%s<--------------------\n"%sql)
self.execute_sql(sql)
def get_info_by_name(self):
'''能防范sql注入'''
name = input("请输入要查询的商品名:")
param = list()
param.append(name)
sql = '''select * from goods where name =%s ;'''
print("---------->%s<--------------------\n"%sql)
self.cursor.execute(sql,param[0]) #可以防止sql注入,在写sql时不要自己拼接sql语句
result = self.cursor.fetchall()
for temp in result:
print(temp)
def add_brand(self):
'''显示所有商品信息'''
brand_name = input("请输入品牌名字:")
sql = '''insert into goods_brand(name) values("%s") '''%(brand_name,)
self.cursor.execute(sql)
self.conn.commit()
@staticmethod
def print_menu():
'''打印菜单'''
print("---------------------查询菜单-----------------")
print("1、查询所有商品信息\n")
print("2、查询所有商品分类\n")
print("3、查询所有品牌分类\n")
print("4、添加一个品牌\n")
print("5、按名字查询一个商品,没有防范sql注入\n")
print("6、按名字查询一个商品,有 防范sql注入\n")
print("q、退出")
fun_code = input("请输入查询功能码:")
return fun_code
def run(self):
'''运行逻辑'''
#print("run\n")
while self.switch:
fun_code = self.print_menu()
if fun_code == "1":
self.show_all();
elif fun_code == "2":
self.show_cate()
elif fun_code == "3":
self.show_brand()
elif fun_code == "4":
self.add_brand()
elif fun_code == "5":
self.get_info_by_name_no()
elif fun_code == "6":
self.get_info_by_name()
elif fun_code == "q":
break;
else:
print("输入有误,请从新输入\n")
def main():
#1、创建JD实例对象
jd = JD()
#2、运行jd的run方法
jd.run()
if __name__ == "__main__":
main()