Python MySQLdb 用法小结
MySQLdb是Python对MySQL数据库操作的模块,已不再更新了。
MySQLdb版本和安装,请见米扑博客:Python学习入门(4)——连接MySQL
官方介绍 :MySQLdb - A DB API v2.0 compatible interface to MySQL. This package is a wrapper around _mysql, which mostly implements the MySQL C API. MySQLdb is an thread-compatible interface to the popular MySQL database server that provides the Python database API.
它其实相当于翻译了对应C的接口。
使用这种数据库接口大多是就是执行连接数据库->执行query->提取数据->关闭连接 这几个步骤。MySQLdb提供比较关键的对象,分别是Connection、Cursor、Result
MySQLdb 常用方法及其参数
1、MySQLdb.Connect(params...)方法的常用参数
参数 | 描述 |
host | 数据库地址 |
port | 数据库端口,默认3306 |
user | 数据库用户名 |
passwd | 数据库密码,默认为空 |
db | 数据库库名,没有默认库 |
connect_timeout | 连接超时时间,单位秒,例如30 |
use_unicode | 结果以unicode字符串返回 |
charset | 插入数据库编码,utf8 |
2、连接对象返回的connect()函数
参数 | 描述 |
commit() | 提交事务。对支持事务的数据库和表,如果提交修改操作,不适用这个方法,则不会写到数据库中 |
rollback() | 事务回滚。对支持事务的数据库和表,如果执行此方法,则回滚当前事务。在没有commit()前提下。 |
cursor([cursorclass]) | 创建一个游标对象。所有的sql语句的执行都要在游标对象下进行。MySQL本身不支持游标,MySQLdb模块对其游标进行了仿真。 |
说明:cursor 默认显示是元组形式,若想返回字典形式,使得更易处理,可用到cursor([cursorclass])中的cusorclass参数。例如:conn.cursor(MySQLdb.cursors.DictCursor) 传入MySQLdb.cursors.DictCursor类,获取的结果是dict字典格式:({'password': u'123456', 'id': 2L, 'name': u'zhangsan'}, {'password': u'123456', 'id': 3L, 'name': u'lisi'}, {'password': u'123456', 'id': 4L, 'name': u'wangwu'})
3、游标对象也提供了几种方法
参数 | 描述 |
close() | 关闭游标 |
execute(sql) | 执行sql语句 |
executemany(sql) | 执行多条sql语句 |
fetchone() | 从执行结果中取第一条记录 |
fetchmany(n) | 从执行结果中取n条记录 |
fetchall() | 从执行结果中取所有记录 |
scroll(self, value, mode='relative') | 游标滚动 |
1、MySQLdb.Connect(host ,user , passw , db , port)函数中,经常使用的只是这几个参数,但是其实里面还有很多比如字符集、线程安全、ssl等也都是很重要的参数,使用时要身份注意。
2、当使用Connection.query()函数进行query后,connection 对象可以返回两种result,分别是store_result和use_result,其中store_result 将结果集存回client端,而use_result则是结果集保存在server端,并且维护了一个连接,会占用server资源。此时,不可以进行任何其他的查询。建议使用store_result,除非返回结果集(result set)过大或是无法使用limit的情景。
3、提取(fetch)数据的返回形式大多有三种情形。 as a tuple(how=0) ;as dictionaries, key=column or table.column if duplicated(how=1);as dictionaries, key=table.column (how=2)
4、每次fetch,在result内部都会产生数据位置的移动,也就是说假如有10行数据,执行result.fetch_row(3,0),会得到前三行,再执行result.fetch_row(3,0),则会得到中间的三行,所以说fetch会导致position的移动。另外值得注意的是,如果使用use_result,也就是数据存储在server时,在fetch所有的条目之前,不能进行任何的query操作。
5、MySQL本身不支持游标(Cursor),但是MySQLdb对Cursor进行了仿真。重要的执行query方法有execute 和 executemany 。execute方法执行单条sql语句,executemany方法可执行多条sql语句,数据库性能瓶颈很大一部分就在于网络IO和磁盘IO将多个insert放在一起,只执行一次IO,可以有效的提升数据库性能。游标cursor具有fetchone、fetchmany、fetchall三个方法提取数据,每个方法都会导致游标游动,所以必须关注游标的位置。游标的scroll(value, mode)方法可以使得游标进行卷动,mode参数指定相对当前位置(relative)还是以绝对位置(absolute)进行移动。
6、MySQLdb提供了很多函数方法,在官方指南里没有完全罗列,使用者可以用help去看看,里面提供了很多方便的东西。
7、对于MySQL来说,如果使用支持事务的存储引擎,那么每次操作后,commit是必须的,否则不会真正写入数据库,对应rollback可以进行相应的回滚,但是commit后是无法再rollback的。commit() 可以在执行很多sql指令后再一次调用,这样可以适当提升性能。
8、executemany处理过多的命令也不见得一定好,因为数据一起传入到server端,可能会造成server端的buffer溢出,而一次数据量过大,也有可能产生一些意想不到的麻烦。合理,分批次executemany是个不错的办法。
最后,我自己写了个pyMysql模块,主要是对MySQLdb提供的常用方法进行了简单的再次封装,也借此机会好好学习下MySQLdb,以及练习python的编码。
MySQLdb 示例:
#!/usr/bin/env python # -*- coding: utf-8 -*- import MySQLdb: try: conn = MySQLdb.Connect( host='localhost', port=3306, user='root', passwd='mimvp@2016', db='bookstore', charset='utf8') # cursorType = MySQLdb.cursors.Cursor, MySQLdb.cursors.DictCursor, MySQLdb.cursors.SSCursor, MySQLdb.cursors.SSDictCursor cursor = conn.cursor() sql = "select * from authors;" cursor.execute(sql) for i in cursor.fetchall(): print i except Exception, e: print ("Connection Error: " + str(e)) finally: if cursor: cursor.close() cursor = None if conn: conn.close() conn = None
该程序使用的数据库表,采用MyISAM引擎,所以没加上commit(),一般最好还是要加上的。
代码如下:PyMysql.py
#-*- encoding:gb2312 -*- ''' Create 2012-01-12 Update 2020-06-20 @author: mimvp.com ''' import MySQLdb import MySQLdb.cursors # 查询结果集 STORE_RESULT_MODE = 0 USE_RESULT_MODE = 1 # 结果集的游标模式 CURSOR_MODE = 0 DICTCURSOR_MODE = 1 SSCURSOR_MODE = 2 SSDICTCURSOR_MODE = 3 # 获取值个数 FETCH_ONE = 0 FETCH_MANY = 1 FETCH_ALL = 2 class PyMysql: def __init__(self): self.conn = None pass def newConnection(self, host, port, user, passwd, defaultdb): """ 建立一个新连接, 指定host、端口port、用户名、密码、默认数据库 """ self.conn = MySQLdb.Connect(host, port, user, passwd, defaultdb) if self.conn.open == False: raise None def closeConnnection(self): """ 关闭当前连接 """ self.conn.close() def query(self, sqltext, mode = STORE_RESULT_MODE): """ 作用: 使用connection对象的query方法, 并返回一个元组(影响行数(int), 结果集(result)) 参数: sqltext : SQL执行语句 mode : 结果集模式, mode=STORE_RESULT_MODE 表示返回store_result, mode=USESTORE_RESULT_MODE 表示返回use_result 返回: 元组( 影响行数(int), 结果集(result) ) """ if self.conn == None or self.conn.open == False : return -1 # 查询SQL语句 self.conn.query(sqltext) if mode == 0 : result = self.conn.store_result() elif mode == 1 : result = self.conn.use_result() else : raise Exception("mode value is wrong.") return (self.conn.affected_rows(), result) def fetch_query_result(self, result, maxrows = 1, how = 0, moreinfo = False): """ 作用: 获取查询结果集 参数: result : query后的结果集合 maxrows : 返回的最大行数 how : 以何种方式存储结果 (0: tuple, 1: dictionaries with columnname, 2: dictionaries with table.columnname) moreinfo: 表示是否获取更多额外信息(num_fields, num_rows, num_fields) 返回: 元组(数据集, 附加信息(当moreinfo = True) 或单一数据集(当moreinfo = False) """ if result == None : return None dataset = result.fetch_row(maxrows, how) if moreinfo is False : return dataset else : num_fields = result.num_fields() num_rows = result.num_rows() field_flags = result.field_flags() info = (num_fields, num_rows, field_flags) return (dataset, info) def execute(self, sqltext, args = None, mode = CURSOR_MODE, many = False): """ 作用: 使用游标(cursor)的execute 执行query 参数: sqltext : SQL执行语句 args : sqltext的参数 mode : 以何种方式返回数据集 CURSOR_MODE = 0 : store_result , tuple DICTCURSOR_MODE = 1 : store_result , dict SSCURSOR_MODE = 2 : use_result , tuple SSDICTCURSOR_MODE = 3 : use_result , dict many : 是否执行多行操作(executemany) 返回: 元组( 影响行数(int), 游标(Cursor) ) """ if mode == CURSOR_MODE : currType = MySQLdb.cursors.Cursor elif mode == DICTCURSOR_MODE : currType = MySQLdb.cursors.DictCursor elif mode == SSCURSOR_MODE : currType = MySQLdb.cursors.SSCursor elif mode == SSDICTCURSOR_MODE : currType = MySQLdb.cursors.SSDictCursor else : raise Exception("mode value is wrong") # 游标类型 curr = self.conn.cursor(cursorclass = currType) line = 0 if many == False : if args == None : line = curr.execute(sqltext) else : line = curr.execute(sqltext, args) else : if args == None : line = curr.executemany(sqltext) else : line = curr.executemany(sqltext, args) return (line , curr) def fetch_execute_result(self, cursor, mode = FETCH_ONE, rows = 1): """ 作用: 提取cursor获取的数据集 参数: cursor : 游标 mode : 执行提取模式, FETCH_ONE : 提取一个; FETCH_MANY : 提取rows个; FETCH_ALL : 提取所有 rows : 提取行数 返回: fetch数据集 """ if cursor == None : return if mode == FETCH_ONE : return cursor.fetchone() elif mode == FETCH_MANY : return cursor.fetchmany(rows) elif mode == FETCH_ALL : return cursor.fetchall() if __name__=="__main__" : print help (PyMysql)
测试代码:
#-*- encoding:gb2312 -*- import PyMysql """ bookstore.authors 这张表很简单, 本文主要的所有操作都针对该表。 +--------------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+-------------+------+-----+---------+----------------+ | author_id | int(11) | NO | PRI | NULL | auto_increment | | author_last | varchar(50) | YES | | NULL | | | author_first | varchar(50) | YES | MUL | NULL | | | country | varchar(50) | YES | | NULL | | +--------------+-------------+------+-----+---------+----------------+ """ def printAuthors(res, mode = 0, lines = 0): """ 格式化打印日志 """ # 打印输出格式: ******************** lines: 10 ******************** print "*"*20, " lines: ", lines, " ", "*"*20 if mode == 0 : for author_id , author_last , author_first , country in res : print "ID : %s , Author_last : %s , Author_First : %s , Country : %s" \ % (author_id , author_last , author_first , country ) else : for item in res : print "-----------" for key in item.keys(): print key, " : ", item[key] # 建立MySQL连接 mysql = PyMysql.PyMysql() mysql.newConnection( host = "localhost", port = 3306, user = "root", passwd = "peterbbs", defaultdb = "bookstore") sqltext = "select * from authors order by author_id asc;" lines, res = mysql.query(sqltext, mode = PyMysql.STORE_RESULT_MODE) dataset = mysql.fetch_query_result(res, maxrows = 20, how = 0, moreinfo = False) # 打印日志 printAuthors(dataset, 0, lines) # 插入多行 sqltext = "insert into authors (author_last, author_first, country) values (%s,%s,%s)" args = [('aaaaaa','bbbbbb','cccccc'),('dddddd','eeeeee','ffffff'),('gggggg','hhhhhh','iiiiii')] lines, cur = mysql.execute(sqltext, args, mode = PyMysql.DICTCURSOR_MODE, many = True) print "*"*20, lines, "行被插入 ", "*"*20 # 查询多行 sqltext = "select * from authors order by author_id " # 调用cursor.execute方法,得到result lines, cur = mysql.execute(sqltext, mode = PyMysql.DICTCURSOR_MODE) # 提取数据 data = mysql.fetch_executeresult(cur, mode = PyMysql.FETCH_MANY, rows = 20) printAuthors(data,1,lines) # 打印 mysql.closeConnnection() # 关闭连接
测试输出:
******************** lines: 5 ******************** ID : 1 , Author_last : Greene , Author_First : Graham , Country : United Kingdom ID : 4 , Author_last : Peter , Author_First : David , Country : China ID : 5 , Author_last : mayday , Author_First : Feng , Country : France ID : 6 , Author_last : zhang , Author_First : lixin , Country : France ID : 9 , Author_last : zhang111 , Author_First : lixin , Country : France ******************** 3 行被插入 ******************** ******************** lines: 8 ******************** ----------- country : United Kingdom author_id : 1 author_first : Graham author_last : Greene ----------- country : China author_id : 4 author_first : David author_last : Peter ----------- country : France author_id : 5 author_first : Feng author_last : mayday ----------- country : France author_id : 6 author_first : lixin author_last : zhang ----------- country : France author_id : 9 author_first : lixin author_last : zhang111 ----------- country : cccccc author_id : 53 author_first : bbbbbb author_last : aaaaaa ----------- country : ffffff author_id : 54 author_first : eeeeee author_last : dddddd ----------- country : iiiiii author_id : 55 author_first : hhhhhh author_last : gggggg
参考推荐:
Python连接MySQL、MongoDB、Redis、memcache
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2024-07-29 18:01:37
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!