Loading

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
posted @ 2021-03-10 19:45  吃了好多肉  阅读(138)  评论(0编辑  收藏  举报