个人笔记——SQL数据库与Python交互

这篇笔记详细介绍了如何使用Python与MySQL数据库进行交互,包括创建数据表、插入数据、查询、修改表结构、以及处理SQL注入问题。文中提供了创建连接、获取Cursor对象、执行SQL语句(查询、添加、修改、删除)的步骤,并举例说明了SQL注入的危害和防范措施。

准备数据

创建数据表

-- 创建京东数据库
create database jingdong charset=utf

-- 使用数据库
use jingdong

-- 创建goods数据表
create table goods(id int unsigned primary key auto_increment not null, name varchar(150) not null, cate_name varchar(40) not null, brand_name varchar(40) not null, price decimal(10, 3) not null default 0, is_show bit not null default 1, is_saleoff bit not null default 0);

插入数据

insert into goods values(0,'r510vc 15.6英寸笔记本','笔记本','华硕','3399',default,default);
insert into goods values(0,'y400n 14.0英寸笔记本电脑','笔记本','联想','4999',default,default);
insert into goods values(0,'g150th 15.6英寸游戏本','游戏本','雷神','8499',default,default);
insert into goods values(0,'x550cc 15.6英寸笔记本','笔记本','华硕','2799',default,default);
insert into goods values(0,'x240 超极本','超级本','联想','4999',default,default);
insert into goods values(0,'u330p 13.3英寸超极本','超级本','联想','4299',default,default);
insert into goods values(0,'svp13226scb 触控超极本','超级本','索尼','7999',default,default);
insert into goods values(0,'ipad mini 7.9英寸平板电脑','平板电脑','苹果','1998',default,default);
insert into goods values(0,'ipad air 9.7英寸平板电脑','平板电脑','苹果','3388',default,default);
insert into goods values(0,'ipad mini 配备 retina 显示屏','平板电脑','苹果','2788',default,default);
insert into goods values(0,'ideacentre c340 20英寸一体电脑 ','台式机','联想','3499',default,default);
insert into goods values(0,'vostro 3800-r1206 台式电脑','台式机','戴尔','2899',default,default);
insert into goods values(0,'imac me086ch/a 21.5英寸一体电脑','台式机','苹果','9188',default,default);
insert into goods values(0,'at7-7414lp 台式电脑 linux )','台式机','宏碁','3699',default,default);
insert into goods values(0,'z220sff f4f06pa工作站','服务器/工作站','惠普','4288',default,default);
insert into goods values(0,'poweredge ii服务器','服务器/工作站','戴尔','5388',default,default);
insert into goods values(0,'mac pro专业级台式电脑','服务器/工作站','苹果','28888',default,default);
insert into goods values(0,'hmz-t3w 头戴显示设备','笔记本配件','索尼','6999',default,default);
insert into goods values(0,'商务双肩背包','笔记本配件','索尼','99',default,default);
insert into goods values(0,'x3250 m4机架式服务器','服务器/工作站','ibm','6888',default,default);
insert into goods values(0,'hmz-t3w 头戴显示设备','笔记本配件','索尼','6999',default,default);
insert into goods values(0,'商务双肩背包','笔记本配件','索尼','99',default,default);
  • 简单练习
-- 查询每种类型中最贵的电脑信息
select * from goods 
inner join (
	select cate_name, 
	max(price) as max_price,
	min(price) as min_price, 
	avg(price) as avg_price, 
	count(*) 
	from goods 
	group by cate_name) as goods_new_info 
	on goods.cate_name=goods_new_info.cate_name and 
	goods.price=goods_new_info.max_price);

上述操作相当于将查询的结果作为一个表,再进行查询操作

  • 创建商品分类表
create table if not exists goods_cates(
	id int unsigned primary key auto_increment, 
	name varchar(40) not null);
  • 查询goods表中商品分类,并将分组结果写入到goods_cates数据表
select cate_name from goods group by cate_name;

insert into goods_cates(name) select cate_name from goods group by cate_name;
  • 同步表数据,通过goods_cates数据表来更新goods表
update goods as g inner join goods_cates as c on g.cate_name=c.name set g.cate_name=c.id;
  • 修改表结构
    查看goods表结构会发现,cate_name的类型是varchar但现在改为存储数字了,所以需要重命名并修改类型和约束
alter table goods change cate_name cate_id int unsigned not null;
  • 为了限制cate_id下的数值只能是goods_cates表中的id,需要给其添加外键
alter table goods add foreign key (cate_id) references goods_cates(id);
  • 再对goods表中的brand_name进行以上相同的操作,即新建表并关联外键
-- 显示brand列表
select brand_name from goods group by brand_name;

-- 创建商品分类
! 在创建分表的同时把数值插入!
create table if not exists goods_brands(
	id int unsigned primary key auto_increment, 
	name varchar(40) not null) 
	select brand_name as name from goods group by brand_name;
! 注意这里必须取别名name

-- 更新goods表中的brand_name
update goods as g inner join goods_brands as b on g.brand_name=b.name set g.brand_name=b.id;

-- 重命名brand_name为brand_id并添加外键约束
alter table goods change brand_name brand_id int unsigned not null;
alter table goods add foreign key(brand_id) references goods_brands(id);

再次说明:在实际开发中很少用到外键,会极大降低表更新的效率

  • 如何取消外键?
-- 查看外键名称
show create table goods;
-- 最后会显示创建外键的名称
-- 如:CONSTRAINT `goods_ibfk_1` FOREIGN KEY (`cate_id`) REFERENCES `goods_cates` (`id`),
-- goods_ibfk_1就是外键名称
alter table goods drop foreign key 外键名称;

Python中操作MySQL

步骤

在这里插入图片描述

导入模块

import pymysql
# 如果只用到pymysql模块可以from pymysql import *
# 多模块混用还是使用单独的导入方式

1.创建Connection连接

conn = pymysql.connect(host="localhost", port="3306", user="root", password="123456", database="jingdong", charset="utf8")

2.获取Cursor对象

cursor = conn.cursor()

以上两步是使用的必须操作,之后则根据操作不同编写

使用sql语句

查询
cursor.execute("select * fromo goods;")
'''此时会返回生效的行数,而不是表格 
这是一条查询语句,当执行查询语句的时候,会将查询的结果存储在游标cursor中'''

cursor.fetchone()
'''此条执行后会按次序提取数据,每次提取一行,返回结果是元组'''

cursor.fetchmany(3)
'''从当前次序取3条数据组成元组返回'''

cursor.fetchall()
'''从当前次序显示所有剩余数据'''

...
...
...

cursor.close()
conn.close()
'''查询完后记得关闭游标和连接!!!'''
添加、修改、删除

增删改操作通过execute()进行操作后,需要使用 连接对象.commit() 来提交完成操作

cursor.execute("""insert into goods_cates (name) values ("硬盘")""")
conn.commit()

'''如果输入错误,可以使用rollback()回滚,如下'''
conn.rollback()

关于SQL注入

实验代码

import pymysql


class JD(object):
    def __init__(self):
        self.conn = pymysql.connect(host="localhost", port=3306, user="root", password="123456", database="jingdong", charset="utf8")
        self.cursor = self.conn.cursor()

    def __del__(self):
        self.cursor.close()
        self.conn.close()

    def execute_sql(self, sql):
        self.cursor.execute(sql)
        for temp in self.cursor.fetchall():
            print(temp)

    def show_all_items(self):
        sql = "select * from goods;"
        self.execute_sql(sql)

    def show_cates(self):
        sql = "select * from goods_cates;"
        self.execute_sql(sql)

    def show_brands(self):
        sql = "select * from goods_brands''"
        self.execute_sql(sql)

    def add_brands(self):
        item_name = input("输入新商品分类名称:")
        sql = """insert into goods_brands (name) values('%s')""" % item_name
        self.cursor.execute(sql)
        self.conn.commit()

    def get_info_by_name(self):
        find_name = input("请输入想要查询的商品名:")
        sql = "select * from goods where name='%s';" % find_name
        print("----->%s<-----" % sql)
        self.cursor.execute(sql)

    @staticmethod
    def print_menu():
        print("-----京东-----")
        print("1.所有的商品")
        print("2.所有的商品分类")
        print("3.所有的商品品牌分类")
        print("4.添加一个商品分类")
        print("5.查询指定商品信息")
        return input("请输入功能对应的序号:")

    def run(self):
        while True:
            num = self.print_menu()
            if num == "1":
                self.show_all_items()
            elif num == "2":
                self.show_cates()
            elif num == "3":
                self.show_brands()
            elif num == "4":
                self.add_brands()
            elif num == "5":
                self.get_info_by_name()
            else:
                print("输入有误,请重新输入")


def main():
    # 1.创建京东对象
    jd = JD()

    # 调用run运行
    jd.run()


if __name__ == '__main__':
    main()

当选择5,并且输入 ’ or 1=1 or '1 时,会显示所有的商品信息,这是因为执行了sql语句:
select * from goods where name=’’ or 1=1 or ‘1’;,导致将整个数据库输出
这就是SQL注入

如何防止?

  • 将输入内容存入表格,然后使用execute来自动拼接sql语句和列表,如下
def get_info_by_name(self):
        find_name = input("请输入想要查询的商品名:")
        sql = "select * from goods where name='%s';"
        print("----->%s<-----" % sql)
        self.cursor.execute(sql, [find_name])
        print(self.cursor.fetchall())
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值