什么是mysql缓冲游标wrt python mysql连接器

gpk*_*k27 13 mysql mysql-connector python-3.x mysql-connector-python

有人可以举个例子来理解这个吗?

执行查询后,MySQLCursorBuffered游标从服务器获取整个结果集并缓冲行.对于使用缓冲游标执行的查询,诸如fetchone()之类的行获取方法从缓冲行集中返回行.对于非缓冲游标,在调用行读取方法之前,不会从服务器获取行.在这种情况下,您必须确保在执行同一连接上的任何其他语句之前获取结果集的所有行,否则将引发InternalError(未读结果)异常.

谢谢

Abd*_*dou 11

我可以想到这两种类型Cursor的两种不同的方式.

第一种方法是,如果使用缓冲游标执行查询,则可以通过检查获得返回的行数MySQLCursorBuffered.rowcount.但是,rowcount无缓冲游标的属性-1execute调用方法后立即返回.这基本上意味着尚未从服务器获取整个结果集.此外,rowcount当您从中获取行时,无缓冲游标的属性会增加,而rowcount缓冲游标的属性保持不变,因为您从中获取行.

以下代码段试图说明上述要点:

import mysql.connector


conn = mysql.connector.connect(database='db',
                               user='username',
                               password='pass',
                               host='localhost',
                               port=3306)

buffered_cursor = conn.cursor(buffered=True)
unbuffered_cursor = conn.cursor(buffered=False)

create_query = """
drop table if exists people;
create table if not exists people (
    personid int(10) unsigned auto_increment,
    firstname varchar(255),
    lastname varchar(255),
    primary key (personid)
);
insert into people (firstname, lastname)
values ('Jon', 'Bon Jovi'),
('David', 'Bryan'),
('Tico', 'Torres'),
('Phil', 'Xenidis'),
('Hugh', 'McDonald')
"""

# Create and populate a table
results = buffered_cursor.execute(create_query, multi=True)
conn.commit()

buffered_cursor.execute("select * from people")
print("Row count from a buffer cursor:", buffered_cursor.rowcount)
unbuffered_cursor.execute("select * from people")
print("Row count from an unbuffered cursor:", unbuffered_cursor.rowcount)

print()
print("Fetching rows from a buffered cursor: ")

while True:
    try:
        row = next(buffered_cursor)
        print("Row:", row)
        print("Row count:", buffered_cursor.rowcount)
    except StopIteration:
        break

print()
print("Fetching rows from an unbuffered cursor: ")

while True:
    try:
        row = next(unbuffered_cursor)
        print("Row:", row)
        print("Row count:", unbuffered_cursor.rowcount)
    except StopIteration:
        break
Run Code Online (Sandbox Code Playgroud)

上面的代码段应该返回如下内容:

Row count from a buffered reader:  5
Row count from an unbuffered reader:  -1

Fetching rows from a buffered cursor:
Row: (1, 'Jon', 'Bon Jovi')
Row count: 5
Row: (2, 'David', 'Bryan')
Row count: 5
Row: (3, 'Tico', 'Torres')
Row count: 5
Row: (4, 'Phil', 'Xenidis')
Row count: 5
Row: (5, 'Hugh', 'McDonald')
Row: 5

Fetching rows from an unbuffered cursor:
Row: (1, 'Jon', 'Bon Jovi')
Row count: 1
Row: (2, 'David', 'Bryan')
Row count: 2
Row: (3, 'Tico', 'Torres')
Row count: 3
Row: (4, 'Phil', 'Xenidis')
Row count: 4
Row: (5, 'Hugh', 'McDonald')
Row count: 5
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,rowcount无缓冲游标的属性从-1我们循环生成的结果开始并增加.缓冲光标不是这种情况.

区分差异的第二种方法是首先注意两者中的哪一个(在同一连接下)execute.如果您开始执行尚未完全获取行的未缓冲游标,然后尝试使用缓冲游标执行查询,InternalError则会引发异常,并且将要求您使用或丢弃未缓冲游标返回的内容.以下是插图:

import mysql.connector


conn = mysql.connector.connect(database='db',
                               user='username',
                               password='pass',
                               host='localhost',
                               port=3306)

buffered_cursor = conn.cursor(buffered=True)
unbuffered_cursor = conn.cursor(buffered=False)

create_query = """
drop table if exists people;
create table if not exists people (
    personid int(10) unsigned auto_increment,
    firstname varchar(255),
    lastname varchar(255),
    primary key (personid)
);
insert into people (firstname, lastname)
values ('Jon', 'Bon Jovi'),
('David', 'Bryan'),
('Tico', 'Torres'),
('Phil', 'Xenidis'),
('Hugh', 'McDonald')
"""

# Create and populate a table
results = buffered_cursor.execute(create_query, multi=True)
conn.commit()

unbuffered_cursor.execute("select * from people")
unbuffered_cursor.fetchone()
buffered_cursor.execute("select * from people")
Run Code Online (Sandbox Code Playgroud)

上面的代码段会引发一个InternalError异常,并显示一条消息,指出有一些未读结果.它是什么,基本上说是由无缓冲光标返回的结果需要才可以用相同的连接下的任何游标执行另一个查询被完全消耗.如果更改unbuffered_cursor.fetchone()unbuffered_cursor.fetchall(),则错误将消失.

还有其他不太明显的差异,例如内存消耗.缓冲游标可能会消耗更多内存,因为它们从服务器获取整个结果集并缓冲行.

我希望这证明是有用的.