pymysql
安装: pip install pymysql
一般流程
建立连接
获取游标
执行SQL
提交事务
释放资源
连接Connect
首先建立连接
pymsql.connect()方法返回的Connection实例
conn=pymysql.connect(host='服务器',
user='用户',
password='密码',
port=端口,
db='库名',
charset='字符集')
注意点:port=3306 不能用引号 否则报错
存在中文的时候,连接需要添加charset=‘utf8’,否则中文显示乱码。
connect方法传参
参数 | 说明 |
---|---|
host | 指的是数据库服务器的主机地址 |
user | 连接数据库的用户 |
password | 连接数据库的密码 |
database | 连接的数据库名 |
port | 端口 |
charset | 字符集 |
游标Cursor
操作数据库,必须使用游标,需要先获取一个游标对象
Connection.cursor(cursor=None)方法返回一个新的游标对象
连接没有关闭前,游标对象可以反复使用
cursor参数,可以指定一个Cursor类,如果为None,则使用默认Cursor类
cursor=conn.cursor()
execute()方法
执行SQL语句,返回受影响的行数
这里和java的jdbc有点不一样不管是增删改,还是差返回的都是受影响的行数,而java查返回的是一个结果集,python的查询的返回值可以理解为查到的数量
查询
count=cursor.execute('select * from person')
print(count)
增删改
try:
count=cursor.execute("insert into t_user (id,username,password,hobby,email) values ('1004','dyk','123','乒乓球','111111')")
print(count)
conn.commit() #提交
# 不然无法保存新建或者修改的数据
except Exception as e:
conn.rollback() #回滚
finally:
cursor.close()
conn.close()
插入多行可以写在一个列表里当参数一次性传入
与查寻不同的是:成功需要commit()提交 失败需要rollback()撤销,如果不写提交即便执行成功数据库里面也没有改动
查询
Cursor类的获取查询结果集的方法有
fetchone()方法获取单条数据,使用fetchall()方法获取多条数据获取指定条数fetchmany(size=None)
方法与属性 | 说明 |
---|---|
fetchone() | 获取查询结果集中的一条数据,返回的是一个元组 |
fetchmany(size=None) | size指定返回的行数,None则返回空元组 |
fetchall() | 返回剩下的所有行,如果走到末尾,就返回空元组,否则返回一个元组,其元素是每一行的记录封装的一个元组 |
cursor.rowcount | 这是一个只读属性,并返回执行execute()方法后影响的行数 |
cursor.rownumber | 返回当前行号.可以修改,支持负数 |
cursor.lastrowid | 可以获取到最新自增的ID,也就是最后插入的一条数据ID |
import pymysql
conn=pymysql.connect(host='localhost',user='root',password='123456',database='db3',port=3306,charset='utf8')
cursor=conn.cursor()
try:
count=cursor.execute('select * from person')
#count=cursor.execute("insert into t_user (id,username,password,hobby,email) values ('1005','dyk','123','乒乓球','111111')")
print(count) #1
print(cursor.rowcount) #1
print(cursor.rownumber) #0
info=cursor.fetchone()
print(cursor.rownumber) #1
print(info) #(1, 'dyk1234', 18, datetime.date(2000, 3, 7), '1106649325', 'jm')
print(type(info)) #<class 'tuple'>
conn.commit()
except Exception as e:
conn.rollback()
finally:
if conn:
conn.close()
if cursor:
cursor.close()
import pymysql
conn=pymysql.connect(host='localhost',user='root',password='123456',database='db3',port=3306,charset='utf8')
cursor=conn.cursor()
try:
count=cursor.execute('select * from person')
#count=cursor.execute("insert into t_user (id,username,password,hobby,email) values ('1005','dyk','123','乒乓球','111111')")
print(cursor.rownumber) #0
info=cursor.fetchall()
print(cursor.rownumber) #3
for f in info:
print(f)
conn.commit()
except Exception as e:
conn.rollback()
finally:
if conn:
conn.close()
if cursor:
cursor.close()
#(1, 'dyk1234', 18, datetime.date(2000, 3, 7), '1106649325', 'jm')
#(5, 'cb', 18, datetime.date(2000, 3, 8), '1106649325', 'jm')
#(7, 'dyk1234', 18, datetime.date(2000, 3, 7), '1106649325', 'jm')
注意:fetch操作的是结果集,结果集是保存在客户端的,也就是说fetch的时候,查询已经结束了.
获取的时候,这个类似于文件的读取操作,文件指针,例如先用了fetchall()就相当于走到末尾,再用fetchone就没用了
关于默认获取的数据是元祖类型,如果想要或者字典类型的数据,即:
cursor = conn.cursor(pymysql.cursors.DictCursor)
import pymysql
conn = pymysql.connect(host='localhost', user='root', password='123456', database='db3', port=3306, charset='utf8')
cursor = conn.cursor(pymysql.cursors.DictCursor)
try:
count = cursor.execute('select * from person')
info = cursor.fetchone()
print(info) #{'id': 1, 'name': 'dyk1234', 'age': 18, 'borndate': datetime.date(2000, 3, 7), 'email': '1106649325', 'address': 'jm'}
print(type(info)) #<class 'dict'>
conn.commit()
except Exception as e:
conn.rollback()
finally:
if conn:
conn.close()
if cursor:
cursor.close()
sql注入
SQL注入(SQLi)是一种注入攻击,,可以执行恶意SQL语句。它通过将任意SQL代码插入数据库查询,使攻击者能够完全控制Web应用程序后面的数据库服务器。攻击者可以使用SQL注入漏洞绕过应用程序安全措施;可以绕过网页或Web应用程序的身份验证和授权,并检索整个SQL数据库的内容;还可以使用SQL注入来添加,修改和删除数据库中的记录。
import pymysql
conn=pymysql.connect(host='localhost',user='root',password='123456',database='db3',port=3306,charset='utf8')
cursor=conn.cursor()
username=input('请输入用户名:')
password=input('请输入密码:')
try:
sql = 'select * from login where username="%s" and password="%s"' % (username, password)
cursor.execute(sql)
print(cursor.fetchone())
conn.commit()
except Exception as e:
conn.rollback()
finally:
if conn:
conn.close()
if cursor:
cursor.close()
这样虽然正常的账号密码输入正确和错误也行,但是如果是
例如
如数username的时候输入zhangsan"#
那么密码无论输入什么都会登录成功
因为拼接后的字符串被#给注释掉了
解决注入攻击的方法
参数化查询,可以有效防止注入攻击,并提高查询的效率
Cursor.execute(query,args=None) args必须是元组 列表或字典
有点像java里面的statement和preparestatement的区别
import pymysql
conn=pymysql.connect(host='localhost',user='root',password='123456',database='db3',port=3306,charset='utf8')
cursor=conn.cursor()
username=input('请输入用户名:')
password=input('请输入密码:')
try:
sql = 'select * from login where username=%s and password=%s'
cursor.execute(sql,[username,password])
print(cursor.fetchone())
conn.commit()
except Exception as e:
conn.rollback()
finally:
if conn:
conn.close()
if cursor:
cursor.close()
execute方法中的 %s 占位不需要带引号
还可以批量执行 executemany()
使用with简化连接过程
每次都连接关闭很麻烦,使用上下文管理,简化连接过程
import pymysql
conn = pymysql.connect(host='localhost', user='root', password='123456', database='db3', port=3306, charset='utf8')
with conn.cursor() as cursor:
try:
count = cursor.execute('select * from person')
info = cursor.fetchone()
print(info)
conn.commit()
except Exception as e:
conn.rollback()
finally:
if conn:
conn.close()