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学习入门(4)——连接MySQL

Python+Selenium2 搭建自动化测试环境

Python连接MySQL、MongoDB、Redis、memcache