2017-10-11 73 views
4

有人可以举个例子来理解这个吗?什么是mysql缓冲光标w.r.t python mysql连接器

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

感谢

回答

1

我能想到的两种方式这两种类型的Cursor s为不同的。

第一种方法是,如果使用缓冲游标执行查询,则可以通过检查MySQLCursorBuffered.rowcount来获取返回的行数。但是,调用execute方法后,未缓冲游标的rowcount属性返回-1。这基本上意味着整个结果集尚未从服务器获取。此外,缓存游标的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 

上面的代码应该返回类似以下内容:

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 

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

第二种说明差异的方法是注意两者中的哪一个(在同一连接下)execute。如果你从执行一个没有被缓存的游标开始,然后尝试用缓存的游标执行一个查询,将会引发一个异常,并且你会被要求消耗或抛弃非缓冲游标返回的内容。下面是一个例证:

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") 

的片段上方将引发InternalError例外具有指示的消息,有一些未读的结果。它基本上是说,在使用同一连接下的任何游标执行另一个查询之前,需要充分使用非缓冲游标返回的结果。如果您更改unbuffered_cursor.fetchone()unbuffered_cursor.fetchall(),错误将消失。

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

我希望这证明有用。