Python中操作mysql的pymysql模块详解


Posted in Python onSeptember 13, 2016

前言

pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同。但目前pymysql支持python3.x而后者不支持3.x版本。

本文测试python版本:2.7.11。mysql版本:5.6.24

一、安装

pip3 install pymysql

二、使用操作

1、执行SQL

#!/usr/bin/env pytho
# -*- coding:utf-8 -*-
import pymysql
 
# 创建连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='tkq1', charset='utf8')
# 创建游标
cursor = conn.cursor()
 
# 执行SQL,并返回收影响行数
effect_row = cursor.execute("select * from tb7")
 
# 执行SQL,并返回受影响行数
#effect_row = cursor.execute("update tb7 set pass = '123' where nid = %s", (11,))
 
# 执行SQL,并返回受影响行数,执行多次
#effect_row = cursor.executemany("insert into tb7(user,pass,licnese)values(%s,%s,%s)", [("u1","u1pass","11111"),("u2","u2pass","22222")])
 
 
# 提交,不然无法保存新建或者修改的数据
conn.commit()
 
# 关闭游标
cursor.close()
# 关闭连接
conn.close()

注意:存在中文的时候,连接需要添加charset='utf8',否则中文显示乱码。

2、获取查询数据

#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"
import pymysql

conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='tkq1')
cursor = conn.cursor()
cursor.execute("select * from tb7")

# 获取剩余结果的第一行数据
row_1 = cursor.fetchone()
print row_1
# 获取剩余结果前n行数据
# row_2 = cursor.fetchmany(3)

# 获取剩余结果所有数据
# row_3 = cursor.fetchall()

conn.commit()
cursor.close()
conn.close()

3、获取新创建数据自增ID

可以获取到最新自增的ID,也就是最后插入的一条数据ID

#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"
import pymysql

conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='tkq1')
cursor = conn.cursor()
effect_row = cursor.executemany("insert into tb7(user,pass,licnese)values(%s,%s,%s)", [("u3","u3pass","11113"),("u4","u4pass","22224")])
conn.commit()
cursor.close()
conn.close()
#获取自增id
new_id = cursor.lastrowid      
print new_id

4、移动游标

操作都是靠游标,那对游标的控制也是必须的

注:在fetch数据时按照顺序进行,可以使用cursor.scroll(num,mode)来移动游标位置,如:

cursor.scroll(1,mode='relative') # 相对当前位置移动
cursor.scroll(2,mode='absolute') # 相对绝对位置移动

 

5、fetch数据类型

关于默认获取的数据是元祖类型,如果想要或者字典类型的数据,即:

#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"
import pymysql

conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='tkq1')
#游标设置为字典类型
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("select * from tb7")

row_1 = cursor.fetchone()
print row_1#{u'licnese': 213, u'user': '123', u'nid': 10, u'pass': '213'}

conn.commit()
cursor.close()
conn.close()

6、调用存储过程

a、调用无参存储过程

#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"

import pymysql

conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='tkq1')
#游标设置为字典类型
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
#无参数存储过程
cursor.callproc('p2')  #等价于cursor.execute("call p2()")

row_1 = cursor.fetchone()
print row_1


conn.commit()
cursor.close()
conn.close()

b、调用有参存储过程

#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"

import pymysql

conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='tkq1')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

cursor.callproc('p1', args=(1, 22, 3, 4))
#获取执行完存储的参数,参数@开头
cursor.execute("select @p1,@_p1_1,@_p1_2,@_p1_3")  #{u'@_p1_1': 22, u'@p1': None, u'@_p1_2': 103, u'@_p1_3': 24}
row_1 = cursor.fetchone()
print row_1


conn.commit()
cursor.close()
conn.close()

三、关于pymysql防注入

 1、字符串拼接查询,造成注入

正常查询语句:

#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"
import pymysql

conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='tkq1')
cursor = conn.cursor()
user="u1"
passwd="u1pass"
#正常构造语句的情况
sql="select user,pass from tb7 where user='%s' and pass='%s'" % (user,passwd)
#sql=select user,pass from tb7 where user='u1' and pass='u1pass'
row_count=cursor.execute(sql) row_1 = cursor.fetchone()
print row_count,row_1

conn.commit()
cursor.close()
conn.close()

构造注入语句:

#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"
import pymysql

conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='tkq1')
cursor = conn.cursor()

user="u1' or '1'-- "
passwd="u1pass"
sql="select user,pass from tb7 where user='%s' and pass='%s'" % (user,passwd)

#拼接语句被构造成下面这样,永真条件,此时就注入成功了。因此要避免这种情况需使用pymysql提供的参数化查询。
#select user,pass from tb7 where user='u1' or '1'-- ' and pass='u1pass'

row_count=cursor.execute(sql)
row_1 = cursor.fetchone()
print row_count,row_1


conn.commit()
cursor.close()
conn.close()

 

 2、避免注入,使用pymysql提供的参数化语句

正常参数化查询

#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"

import pymysql

conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='tkq1')
cursor = conn.cursor()
user="u1"
passwd="u1pass"
#执行参数化查询
row_count=cursor.execute("select user,pass from tb7 where user=%s and pass=%s",(user,passwd))
row_1 = cursor.fetchone()
print row_count,row_1

conn.commit()
cursor.close()
conn.close()

构造注入,参数化查询注入失败。

#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"
import pymysql

conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='tkq1')
cursor = conn.cursor()

user="u1' or '1'-- "
passwd="u1pass"
#执行参数化查询
row_count=cursor.execute("select user,pass from tb7 where user=%s and pass=%s",(user,passwd))
#内部执行参数化生成的SQL语句,对特殊字符进行了加\转义,避免注入语句生成。
# sql=cursor.mogrify("select user,pass from tb7 where user=%s and pass=%s",(user,passwd))
# print sql
#select user,pass from tb7 where user='u1\' or \'1\'-- ' and pass='u1pass'被转义的语句。

row_1 = cursor.fetchone()
print row_count,row_1

conn.commit()
cursor.close()
conn.close()

结论:excute执行SQL语句的时候,必须使用参数化的方式,否则必然产生SQL注入漏洞。

3、使用存mysql储过程动态执行SQL防注入

使用MYSQL存储过程自动提供防注入,动态传入SQL到存储过程执行语句。

delimiter \\
DROP PROCEDURE IF EXISTS proc_sql \\
CREATE PROCEDURE proc_sql (
  in nid1 INT,
  in nid2 INT,
  in callsql VARCHAR(255)
  )
BEGIN
  set @nid1 = nid1;
  set @nid2 = nid2;
  set @callsql = callsql;
    PREPARE myprod FROM @callsql;
--   PREPARE prod FROM 'select * from tb2 where nid>? and nid<?';  传入的值为字符串,?为占位符
--   用@p1,和@p2填充占位符
    EXECUTE myprod USING @nid1,@nid2;
  DEALLOCATE prepare myprod;

END\\
delimiter ;
set @nid1=12;
set @nid2=15;
set @callsql = 'select * from tb7 where nid>? and nid<?';
CALL proc_sql(@nid1,@nid2,@callsql)

pymsql中调用

#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"
import pymysql

conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='tkq1')
cursor = conn.cursor()
mysql="select * from tb7 where nid>? and nid<?"
cursor.callproc('proc_sql', args=(11, 15, mysql))

rows = cursor.fetchall()
print rows #((12, 'u1', 'u1pass', 11111), (13, 'u2', 'u2pass', 22222), (14, 'u3', 'u3pass', 11113))
conn.commit()
cursor.close()
conn.close()

四、使用with简化连接过程

每次都连接关闭很麻烦,使用上下文管理,简化连接过程

#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"

import pymysql
import contextlib
#定义上下文管理器,连接后自动关闭连接
@contextlib.contextmanager
def mysql(host='127.0.0.1', port=3306, user='root', passwd='', db='tkq1',charset='utf8'):
  conn = pymysql.connect(host=host, port=port, user=user, passwd=passwd, db=db, charset=charset)
  cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
  try:
    yield cursor
  finally:
    conn.commit()
    cursor.close()
    conn.close()

# 执行sql
with mysql() as cursor:
  print(cursor)
  row_count = cursor.execute("select * from tb7")
  row_1 = cursor.fetchone()
  print row_count, row_1

总结

以上就是关于Python中pymysql模块的全部内容,希望对大家学习或使用python能有一定的帮助,如果有疑问大家可以留言交流。

Python 相关文章推荐
Python中使用wxPython开发的一个简易笔记本程序实例
Feb 08 Python
通过代码实例展示Python中列表生成式的用法
Mar 31 Python
编写Python脚本来获取mp3文件tag信息的教程
May 04 Python
在Django框架中运行Python应用全攻略
Jul 17 Python
Python在图片中添加文字的两种方法
Apr 29 Python
基于Python实现的微信好友数据分析
Feb 26 Python
python使用tornado实现登录和登出
Jul 28 Python
学习python的前途 python挣钱
Feb 27 Python
python飞机大战pygame游戏框架搭建操作详解
Dec 17 Python
PyQt5 closeEvent关闭事件退出提示框原理解析
Jan 08 Python
python中resample函数实现重采样和降采样代码
Feb 25 Python
python GUI库图形界面开发之PyQt5线程类QThread详细使用方法
Feb 26 Python
python常用函数详解
Sep 13 #Python
python如何查看系统网络流量的信息
Sep 12 #Python
Python爬取三国演义的实现方法
Sep 12 #Python
python 读写、创建 文件的方法(必看)
Sep 12 #Python
Python读写Json涉及到中文的处理方法
Sep 12 #Python
详细介绍Python的鸭子类型
Sep 12 #Python
Python 读写文件和file对象的方法(推荐)
Sep 12 #Python
You might like
DEDE采集大师官方留后门的删除办法
2011/01/08 PHP
PHP用户验证和标签推荐的简单使用
2016/10/31 PHP
发现的以前不知道的函数
2006/09/19 Javascript
创建一个复制UBB软件信息的链接或按钮的js代码
2008/01/06 Javascript
jquery text,radio,checkbox,select操作实现代码
2009/07/09 Javascript
JQuery 应用 JQuery.groupTable.js
2010/12/15 Javascript
Jquery截取中文字符串的实现代码
2010/12/22 Javascript
javascript中关于执行环境的杂谈
2011/08/14 Javascript
原生Js实现元素渐隐/渐现(原理为修改元素的css透明度)
2013/06/24 Javascript
javascript利用apply和arguments复用方法
2013/11/25 Javascript
ie 7/8不支持trim的属性的解决方案
2014/05/23 Javascript
JavaScript自定义等待wait函数实例分析
2015/03/23 Javascript
JavaScript中reduce()方法的使用详解
2015/06/09 Javascript
Angularjs 实现分页功能及示例代码
2016/09/14 Javascript
axios对请求各种异常情况处理的封装方法
2018/09/25 Javascript
小程序实现列表点赞功能
2018/11/02 Javascript
微信小程序一周时间表功能实现
2019/10/17 Javascript
Node.js 在本地生成日志文件的方法
2020/02/07 Javascript
pygame 精灵的行走及二段跳的实现方法(必看篇)
2017/07/10 Python
用 Python 爬了爬自己的微信朋友(实例讲解)
2017/08/25 Python
Python正则表达式指南 推荐
2018/10/09 Python
Python Numpy:找到list中的np.nan值方法
2018/10/30 Python
PyQt5显示GIF图片的方法
2019/06/17 Python
对Django外键关系的描述
2019/07/26 Python
python实现高斯投影正反算方式
2020/01/17 Python
pycharm专业版远程登录服务器的详细教程
2020/09/15 Python
利用纯CSS3实现文字向右循环闪过效果实例(可用于移动端)
2017/06/15 HTML / CSS
什么是View State?
2013/01/27 面试题
自我推荐书
2013/12/04 职场文书
大学生水果店创业计划书
2014/01/28 职场文书
技校毕业生自荐信范文
2014/03/07 职场文书
2015年上半年计生工作总结
2015/03/30 职场文书
2015年食品安全工作总结
2015/05/15 职场文书
新娘婚礼致辞
2015/07/27 职场文书
2016年学校党支部公开承诺书
2016/03/25 职场文书
golang如何去除多余空白字符(含制表符)
2021/04/25 Golang