从图中可以看出,在 Python 中操作数据库,要经过五个步骤,分别是连接数据库,获取游标,数据库操作,关闭游标,关闭数据库连接。
数据库资源
1.导入模块
from pymysql import connect
2.Connection 对象 目的:用于建立代码与数据库的连接
使用这三个创建连接都可以
connect = Connection = Connect
前两个对后一个函数进行引用
创建连接对象 conn=connect(参数列表)
4.提交数据 conn.commit()
5.撤销数据 conn.rollback()
6.通过连接获取游标 cur = conn.cursor()返回Cursor对象,用于执行sql语句并获得结果
7.Cursor游标对象 目的: 执行sql语句
8.获取Cursor对象 cur = conn.cursor()
9.使用游标执行SQL语句 cur.execute(operation , [parameters])
10.执行SQL语句,返回受影响的行数,主要用于执行insert、update、delete语句
11.获取结果集中的一条 cur.fetchone() 返回一个元组 如 (1,‘妲己’,18)
12.获取结果集中的一条 cur.fetchmany(2) 返回一个元组 如 ((1,‘妲己’,18),2,‘公孙离’,20))
13.获取结果集中的所有 cur.fetchall() 执行查询时,获取结果集的所有行,一行构成一个元组,再将这些元组装入一个元组返回. 如((1,‘妲己’,18),(2,‘公孙离’,20),(3,‘姜子牙’,28))
14.关闭游标 cur.close()
-- 创建数据库
create database python_db charset=utf8;
-- 使用数据库
use python_db;
-- students表
create table students(
id int unsigned primary key auto_increment not null,
name varchar(20) default '',
age tinyint unsigned default 0,
height decimal(5,2),
gender enum('男','女','中性','保密') default '保密',
cls_id int unsigned default 0,
is_delete int default 0
);
-- classes表
create table classes (
id int unsigned auto_increment primary key not null,
name varchar(30) not null
);
-- 向students表中插入数据
insert into students values
(0,'小明',18,180.00,2,1,0),
(0,'小月月',18,180.00,2,2,1),
(0,'彭于晏',29,185.00,1,1,0),
(0,'刘德华',59,175.00,1,2,1),
(0,'黄蓉',38,160.00,2,1,0),
(0,'凤姐',28,150.00,4,2,1),
(0,'王祖贤',18,172.00,2,1,1),
(0,'周杰伦',36,NULL,1,1,0),
(0,'程坤',27,181.00,1,2,0),
(0,'刘亦菲',25,166.00,2,2,0),
(0,'金星',33,162.00,3,3,1),
(0,'静香',12,180.00,2,4,0),
(0,'郭靖',12,170.00,1,4,0),
(0,'周杰',34,176.00,2,5,0);
-- 向classes表中插入数据
insert into classes values (0, "python_01期"), (0, "python_02期");
# 导入模块
from pymysql import connect
# 连接数据库
conn = connect(host='localhost', port=3306, database='python_db', user='root', password='123123',charset='utf8')
# 获取游标
cur = conn.cursor()
# 以字符串形式书写SQL语句,因为SQL语句中也会出现字符串,所以建议使用 ```引号形式将SQL诗句引起来
sql_str = '''select * from students;'''
# 执行SQL语句
row_count = cur.execute(sql_str)
# 显示执行 SQL 语句影响的行数
print(row_count)
# 获取一条记录
row_one = cur.fetchone()
# 显示获取的记录
print(row_one)
# 获取多条记录
row_many = cur.fetchmany(4)
# 遍历输出所有的结果
for t in row_many:
print(t)
# 获取所有的数据
row_all = cur.fetchall()
# 遍历输出所有的结果
for t in row_all:
print(t)
# 关闭游标
cur.close()
# 关闭数据库
conn.close()
注意:因为在获取数据时,游标是移动的,所以前面取过的数据,后面不会再取了。
# 导入模块
from pymysql import connect
# 连接数据库
conn = connect(host='localhost', port=3306, database='python_db', user='root', password='123123',charset='utf8')
# 获取游标
cur = conn.cursor()
# 以字符串形式书写SQL语句
# sql_str = '''insert into students values(0,'新来的',20,180,'男',1,1)'''
# sql_str = '''update students set name = '王钢蛋' where name = '新来的'; '''
sql_str = '''delete from students where name='王钢蛋'; '''
# 执行SQL语句
row_count = cur.execute(sql_str)
# 在执行增删改操作时,需要向数据库提交操作,否则操作不成功
conn.commit()
# 关闭游标
cur.close()
# 关闭数据库
conn.close()
# 导入模块
from pymysql import connect
# 连接数据库
conn = connect(host='localhost', port=3306, database='python_db', user='root', password='123123',charset='utf8')
# conn.autocommit(True)
# 获取游标
cur = conn.cursor()
# 以字符串形式书写SQL语句
sql_str = '''insert into students values(0,'新来的',20,180,'男',1,1)'''
#插入10条数据
for i in range(10):
# 执行SQL语句
row_count = cur.execute(sql_str)
# 在执行增删改操作时,如果不想提交前面的修改操作,可以使用 rollback 回滚取消操作
conn.rollback()
# 关闭游标
cur.close()
# 关闭数据库
conn.close()
create database JDDB charset=utf8;
use JDDB
source JDDB.sql
import pymysql
class JD(object):
def __init__(self):
self.dic = {0: self.__close,
1: self.__fetch_all_info,
2: self.__fetch_cate,
3: self.__fetch_brand,
4: self.__add_info,
5: self.__find_info,
6: self.__find_info_safe
}
# user,和password换成你的root和密码
self.__conn = pymysql.Connect(host="localhost",
port=3306,
database="JDDB",
user="demouser",
password="demopassword",
charset="utf8")
self.__cur = self.__conn.cursor()
def __show_result(self, result):
# print(type(result)) #
for r in result:
print(r)
# 查询所有商品信息
def __fetch_all_info(self):
sql = ''' select * from goods '''
affected = self.__cur.execute(sql)
print("influenced %d row" % affected)
self.__show_result(self.__cur.fetchall())
# 查询种类信息
def __fetch_cate(self):
sql = ''' select * from goods_cates '''
self.__cur.execute(sql)
self.__show_result(self.__cur.fetchall())
# 查询品牌信息
def __fetch_brand(self):
sql = ''' select * from goods_brands '''
self.__cur.execute(sql)
self.__show_result(self.__cur.fetchall())
# 添加一个商品类型
def __add_info(self):
goods_type = input("please input a new goods type: ")
sql = ''' insert into goods_cates(name) values ("%s") '''
self.__cur.execute(sql, goods_type)
self.__conn.commit()
# 通过ID 查找商品
def __find_info(self):
# 当输入 "id or True" 时会发生sql注入,看到本不该看到的东西
goods_type = input("please input a ID of cates: ")
sql = ''' select * from goods where id=%s''' % goods_type
self.__cur.execute(sql)
self.__show_result(self.__cur.fetchall())
# 通过ID 查找商品 防SQL注入
def __find_info_safe(self):
goods_type = input("please input a ID of cates: ")
# 此处不同于python的字符串格式化,必须全部使用%s占位
sql = ''' select * from goods where id=%s'''
# 通过参数化列表(元组)防止这种攻击,但是会产生一个warning,可以直接存储到日志log中
self.__cur.execute(sql, (goods_type,))
self.__show_result(self.__cur.fetchall())
# 关闭连接,退出
def __close(self):
self.__cur.close()
self.__conn.close()
exit()
def run(self):
while True:
print('*' * 50)
print("1查询所有商品信息")
print("2查询所有商品在种类信息")
print("3查询所有商品在品牌信息")
print("4添加商品种类")
print("5根据id查询商品信息")
print("6根据id查询商品信息安全方式")
print("0退出")
print('*' * 50)
option = int(input("please input your option: "))
try:
self.dic[option]()
# string() # eval()
except KeyError:
print("enter is error! ")
def main():
jd = JD()
jd.run()
if __name__ == '__main__':
main()
什么是SQL注入?
产生原因: 后台对用户提交的带有恶意的数据和 SQL 进行字符串方式的拼接,得到了脱离原意的 SQL 语句,从而影响了 SQL 语句的语义,最终产生数据泄露的现象。
如何防止: SQL 语句的参数化, 将 SQL 语句的所有数据参数存在一个列表中传递给 execute 函数的第二个参数