pymysql模块
pymysql模块
pymysql模块是python一个操作mysql的模块。非内置模块,需要安装:
pip3 install pymysql
基本使用
import pymysql
# 连接数据库
conn = pymysql.connect(
host='127.0.0.1', # 指定ip
port=3306, # 指定端口,注意端口号为int类型
user='root', # 用户名
password='1233', # 用户密码
charset='utf8mb4', # 编码不要加-
database='day38', # 指定操作的库
)
# cursor = conn.cursor() # 生成游标对象,用来执行SQL语句
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) # 该参数将查询结果变为字典类型,key为字段名,value为值。
sql = 'select * from teacher;'
res = cursor.execute(sql)
print(res) # 得到的返回值为受影响的行数。
# 拿到一条查询结果,元组类型,加参数后为字典。
# print(cursor.fetchone())
# 拿到指定条数的记录,一行记录为一个元组,多条记录合并为一个大元组。
# 加参数后为一个列表内嵌套着多个字典
# print(cursor.fetchmany(2))
# 拿到剩余所有的记录,大元组嵌套小元组,加参数后为列表嵌套多个字典。
print(cursor.fetchall())
# print(cursor.fetchall()) # 每读一条记录,指针都会向后移一位,所有记录都拿完后就无法再取值,所以结果为空元组或空列表。
# 移动指针
cursor.scroll(1,'relative') # 相对指针当前位置向后移动1位。
cursor.scroll(1,'abslute') # 从起始位置向后移动1位。
cursor.close() # 关闭游标
conn.close() # 关闭连接
SQL注入
利用一些语法的特性,书写一些特定的语句实现固定的语法。
MySQL利用的是MySQL的注释语法。
例如写一个登录功能:
import pymysql
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='1233',
database='db1',
charset='utf8',
)
cursor = conn.cursor()
name = input('name: ').strip()
password = input('password: ').strip()
# name字段和password字段为字符,要带引号,分号带不带无所谓
sql = f'select * from user_info where name = "{name}" and password = "{password}";'
res = cursor.execute(sql)
if res:
print('登录成功!')
else:
print('登录失败!')
cursor.close()
conn.close()
当正常输入用户名和密码时能够进行正常的判断,但如果输入的是下列特殊语句,就会造成误判甚至危害:
1、只知道用户名,密码为空或错误也能登陆成功
name: chirou' -- 必须有一个任意字符,注意--后面要带一个空格,引号要匹配
password:
登陆成功!
通过这种方式,SQL语句实际变成了:
select * from user_info where name = "chirou" -- a" and password = "";
仅判断了用户名,后面都被注释掉,不再进行判断。
2、用户名和密码都不知道也能登陆成功
name: xxx" or 1=1 -- asd
password:
登录成功!
SQL语句变成了:
select * from user_info where name = "xxx" or 1=1 -- asd" and password = "";
只要or
后面的条件为真就能总体为真。
解决方式
1、限制用户输入的字符格式,尽量不要有特殊符号。
2、不要自己用Python格式化字符串拼接。
execute方法可以过滤掉特殊符号,帮我们完成拼接操作:
sql = 'select * from user_info where name=%s and password=%s' # execute只能识别%s
res = cursor.execute(sql,(name,password)) # 元组或列表都行,注意顺序。
这样就能避免SQL注入问题。
pymysql的增删改查
import pymysql
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='1233',
database='db1',
charset='utf8',
autocommit=True, # 自动提交
)
cursor = conn.cursor(pymysql.cursors.DictCursor)
# 增
# sql = 'insert into user_info(name,password) values(%s,%s)'
# rows = cursor.execute(sql, ('duorou', 123))
# print(rows)
# 添加多条数据
sql = 'insert into user_info(name,password) values(%s,%s)'
rows = cursor.executemany(sql,[('aaa',123),('bbb',123),('ccc',123)])
print(rows)
# 改
# sql = 'update user_info set name="hahaha" where id = 7'
# rows = cursor.execute(sql)
# print(rows)
# 删
# sql = 'delete from user_info where name="hahaha"'
# rows = cursor.execute(sql)
# print(rows)
# 查
# sql = 'select * from user_info'
# rows = cursor.execute(sql)
# print(rows)
# 对于增删改操作,涉及到数据的变动,所以不会直接在数据看生效,需要进行二次确认,提交操作
# conn.commit() # 也可以在建立连接对象时指定autocommit为True,自动提交
cursor.close()
conn.close()
获取插入的最后一条记录的自增ID
import pymysql
conn=pymysql.connect(host='localhost',port=3306,user='root',password='1233',database='db1',charset='utf8')
cursor=conn.cursor()
sql='insert into user_info(name,password) values("xxx","123");'
rows=cursor.execute(sql)
print(cursor.lastrowid) #在插入语句后查看
conn.commit()
cursor.close()
conn.close()
调用存储过程
cursor.callproc('p1',(1,5,10)) # 第一个参数是存储过程的名称,第二个参数是存储过程的参数。
print(cursor.fetchall()) # 查看存储过程所显示的结果。
pymysql模块会将传给存储过程的参数先定义为mysql的变量,通过变量将实际的值传进去,变量命名为:
@_p1_0 = 1
@_p1_1 = 5
@_p1_2 = 10