在MySQL官网有关于Python版的MySQL Connector的使用介绍:MySQL Connector/Python Developer Guide

但似乎这个介绍中的例子都过于浅显,尤其是对于执行MySQL命令后获取值的部分;这两天看了看源码发现还有好多新东西。

来自官网的介绍似乎是要这样使用:

import mysql.connector
db = {
    'user': 'root',
    'password': '123456',
    'database': '123061'
}
cnx = mysql.connector.connect(
    user=db['user'], password=db['password'], database=db['database'])
cursor = cnx.cursor()
query = "SELECT name FROM station"
cursor.execute(query)
for (name,) in cursor:
    print(name)
cursor.close()
cnx.close()

简单而言,

cursor = cnx.cursor()

实际上是创建了类MySQLCursor的一个实例,当

cursor.execute(query)

后,数据库操作得到的每一条结果都作为一个元组(tuplecursor实际上就是作为一个迭代器(iterator),每次使用方法__next__()即返回一条结果。

当迭代器中无值,即每条结果都返回后,如果继续执行__next__(),则会产生StopIteration错误

所以如果不希望使用for...in...的话,可以使用:

try:
    cursor.__next__()
except StopIteration:
    print('no more result')

另外还需要注意的是,如果迭代器中的结果没有全部取出,是不能再次执行cursor.execute(),也就是说不能在for...in...循环内再次操作数据库,而是需要首先将值全部取出。

实际上,数据库操作返回的结果也并不一定要是tuple,还可以是dictionary,只需要在创建cursor时声明:

cursor = cnx.cursor(dictionary = True)

返回的dictionary中key都是数据库table中的字段名,而如果希望key不是字段名,可以在MySQL语句中声明,如:

query = "SELECT name AS 名字 FROM station"

这样返回的dictionary中key即“名字”


__next__()方法的源码:

def __next__(self):
    """
    Used for iterating over the result set. Calles self.fetchone()
    to get the next row.
    """
    try:
        row = self.fetchone()
    except errors.InterfaceError:
        raise StopIteration
    if not row:
        raise StopIteration
    return row

可以看到每次执行__next__()实际上都是在执行fetchone()

fetchone()的源码:

def fetchone(self):
    """Returns next row of a query result set

    Returns a tuple or None.
    """
    row = self._fetch_row()
    if row:
        return self._connection.converter.row_to_python(
            row, self.description)
    return None

这里不深究fetchone()了,实际上这里还有fetchmany()fetchall()

def fetchmany(self, size=None):
    res = []
    cnt = (size or self.arraysize)
    while cnt > 0 and self._have_unread_result():
        cnt -= 1
        row = self.fetchone()
        if row:
            res.append(row)
    return res
def fetchall(self):
    if not self._have_unread_result():
        raise errors.InterfaceError("No result set to fetch from.")
    (rows, eof) = self._connection.get_rows()
    if self._nextrow[0]:
        rows.insert(0, self._nextrow[0])
    res = [self._connection.converter.row_to_python(row, self.description)
           for row in rows]
    self._handle_eof(eof)
    rowcount = len(rows)
    if rowcount >= 0 and self._rowcount == -1:
        self._rowcount = 0
    self._rowcount += rowcount
    return res

我觉得fetchall()才是被忽略的好东西,fetchall()返回的是由tuple组成的list,这样避免了for...in...这种讨厌的东西,比如:

cursor.execute(query)
res=cursor.fetchall()