Python使用pymysql操作MySQL数据库:增删改查与防注入详解
本文详细解析Python中使用pymysql模块进行MySQL数据库增删改查的完整流程。通过连接、游标创建、SQL执行及结果获取等步骤,演示了基础查询与登录验证。重点剖析了字符串拼接导致的SQL注入风险,并提供了参数化查询(列表与字典方式)的安全解决方案。同时涵盖commit提交机制、批量操作及fetchone/fetchall等数据读取方法。
Python pymysql模块MySQL操作概述
本文通过具体实例,展示如何在Python中利用pymysql模块实现对MySQL数据库的增加、删除、修改和查询操作,供开发者参考学习。
基础连接与查询执行流程
# -*- coding:utf-8 -*-
import pymysql
user = input('请输入用户名:')
pwd = input('请输入密码:')
# 1.连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='123', db='t1', charset='utf8')
print(conn)
# 2.创建游标
cursor = conn.cursor()
#注意%s需要加引号
sql = "select * from t1.userinfo where username='%s' and pwd='%s'" %(user, pwd)
print(sql)
# 3.执行sql语句
cursor.execute(sql)
result=cursor.execute(sql) #执行sql语句,返回sql查询成功的记录数目
print(result)
# 关闭连接,游标和连接都要关闭
cursor.close()
conn.close()
if result:
print('登陆成功')
else:
print('登录失败')
以下是具体的执行流程演示。
系统提示输入用户名:lisi,接着输入密码:123。程序输出连接对象信息:<pymysql.connections.Connection object at 0x000001BEFABFE240>,并打印生成的SQL语句:select * from t1.userinfo where username='lisi' and pwd='123'。
验证结果为:登陆成功。
SQL注入风险与攻击原理
二、execute()方法中的SQL注入风险。
常见的攻击方式如下。
#1、SQL注入案例:用户存在,但绕过密码验证 lisi' -- 任意字符 #2、SQL注入案例:用户不存在,同时绕过用户名与密码验证 xxx' or 1=1 -- 任意字符
模拟攻击输入:用户名为sdj;fja;' or 1=1 -- ;j;j;jj;jjkdsjfjsd,密码为123。程序输出连接对象:<pymysql.connections.Connection object at 0x000001EF2BE3E240>,并显示拼接后的危险SQL语句:select * from t1.userinfo where username='sdj;fja;' or 1=1 -- ;j;j;jj;jjkdsjfjsd' and pwd='123'。
由于逻辑被篡改,系统判定为:登陆成功。
针对上述问题的解决方案。
1. 采用列表方式传递参数。
防止SQL注入的参数化查询方案
# 原来是我们对sql进行字符串拼接
# sql="select * from userinfo where name='%s' and password='%s'" %(username,pwd)
# print(sql)
# result=cursor.execute(sql)
#改写为(execute帮我们做字符串拼接,我们无需且一定不能再为%s加引号了)
sql="select * from userinfo where name=%s and pwd=%s" #!!!注意%s需要去掉引号,因为pymysql会自动为我们加上
result=cursor.execute(sql,[user,pwd]) #pymysql模块自动帮我们解决sql注入的问题,只要我们按照pymysql的规矩来。
2. 采用字典方式传递参数。
# -*- coding:utf-8 -*-
import pymysql
user = input('请输入用户名').strip()
pwd = input('请输入密码').strip()
# 连接服务端
conn = pymysql.connect(
host='127.0.0.1',
user='root',
password="123",
database='t1',
port=3306,
charset='utf8'
)
# -- ddadad
# 创建游标对象
cur = conn.cursor()
sql = "select * from userinfo where username = %(name)s and pwd = %(password)s"
print(sql)
# resultNum = cur.execute(sql,[user,pwd])
resultNum = cur.execute(sql,{"name":user,"password":pwd})
print(resultNum)
cur.close()
conn.close()
if resultNum:
print('登陆成功')
else:
print('登陆失败')
数据增删改与事务提交机制
三、增、删、改操作:conn.commit()的使用。
commit()方法的作用:在执行数据库的增、删、改操作时,必须调用提交命令,否则插入或修改的数据不会生效。
基本代码框架如下。
import pymysql
username = input('请输入用户名:')
pwd = input('请输入密码:')
# 1.连接
conn = pymysql.connect(host='localhost', port=3306, user='root', password='123', db='db8', charset='utf8')
# 2.创建游标
cursor = conn.cursor()
--------增删改操作----------------
#一定记得commit
conn.commit()
# 4.关闭游标
cursor.close()
# 5.关闭连接
conn.close()
增加操作——插入一组数据。
sql='insert into userinfo(username,pwd) values(%s,%s)'
effect_row=cursor.execute(sql,(username,pwd)) # effect_row=1
增加操作——插入多组数据。
sql='insert into userinfo(username,pwd) values(%s,%s)'
effect_row=cursor.executemany(sql,[('赵八','112'),('刘九','114'),('封十','911')]) #effect_row=3
删除操作示例。
sql='delete from userinfo where pwd like "%2"'
effect_row=cursor.execute(sql)
修改操作示例。
sql='update userinfo set username = %s where pwd="114"'
effect_row=cursor.execute(sql,'niu') #effect_row=2
**注意变量 effect_row=cursor.execute(...),该返回值表示成功影响的记录条数。**
数据查询与游标移动技巧
四、查询操作:fetchone、fetchmany、fetchall的使用。
数据库表中的现有内容。
mysql> select * from userinfo;
+----+----------+-----+
| id | username | pwd |
+----+----------+-----+
| 1 | mjj | 123 |
| 3 | 张三 | 110 |
| 4 | 李四 | 119 |
+----+----------+-----+
3 rows in set (0.00 sec)
固定的查询代码格式。
import pymysql
# 1.连接
conn = pymysql.connect(host='localhost', port=3306, user='root', password='', db='db8', charset='utf8')
# 2.创建游标
cursor = conn.cursor()
sql = 'select * from userinfo'
cursor.execute(sql)
------------执行的查询--------------
# 4.关闭游标
cursor.close()
# 5.关闭连接
conn.close()
fetchone用于获取一条符合条件的数据,可连续调用,每次获取的是上一条fetchone结果之后的下一条记录。
# 查询第一行的数据
row = cursor.fetchone()
print(row) # (1, 'mjj', '123')
# 查询第二行数据
row = cursor.fetchone()
print(row) # (3, '张三', '110')
fetchall()用于查询所有符合条件的数据。
# 获取所有的数据
rows = cursor.fetchall()
print(rows)
#运行结果
((1, 'mjj', '123'), (3, '张三', '110'), (4, '李四', '119')) 取到的返回值是元组
fetchmany用于获取指定数量的数据条数。
row=cursor.fetchmany(3)
print(row)
cursor.scroll(num,mode='relative|absolute'):当mode设置为absolute时,num参数不能小于0。
cursor.scroll(1,mode='relative') # 相对当前位置移动
cursor.scroll(2,mode='absolute') # 相对绝对位置移动
# 查询第一行的数据
row = cursor.fetchone()
print(row) # (1, 'mjj', '123')
# 查询第二行数据
row = cursor.fetchone() # (3, '张三', '110')
print(row)
cursor.scroll(-1,mode='relative') #设置之后,光标相对于当前位置往前移动了一行,所以打印的结果为第二行的数据
row = cursor.fetchone()
print(row)
cursor.scroll(0,mode='absolute') #设置之后,光标相对于首行没有任何变化,所以打印的结果为第一行数据
row = cursor.fetchone()
print(row)
更多关于Python数据库操作的技巧,可查看本站专题:《Python常见数据库操作技巧汇总》、《Python数学运算技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》及《Python文件与目录操作技巧汇总》。
希望本文的阐述能对大家的Python程序设计工作有所帮助。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













