0

我正在开发一个程序,将数据库中的行从一个用户克隆到另一个用户。它适用于我选择行,编辑一些值,然后将它们插入回去。

我还需要将新插入的 rowID 与其现有的对应对象一起存储,以便以后可以克隆其他一些链接表。

我的代码如下所示:

import mysql.connector
from collections import namedtuple

con = mysql.connector.connect(host='127.0.0.1')
selector = con.cursor(prepared=True)
insertor = con.cursor(prepared=True)

user_map = {}
selector.execute('SELECT * FROM users WHERE companyID = ?', (56, ))
Row = namedtuple('users', selector.column_names)

for row in selector:
    curr_row = Row._make(row)
    new_row = curr_row._replace(userID=None, companyID=95)

    insertor.execute('INSERT INTO users VALUES(?,?,?,?)', tuple(new_row))
    user_map[curr_row.userID] = insertor.lastrowid

selector.close()
insertor.close()

运行此代码时,我收到以下错误:

mysql.connector.errors.InternalError:找到未读结果

我假设这是因为我试图运行一段INSERT时间我仍在循环SELECT我认为使用两个游标可以解决这个问题。为什么使用多个游标仍然会出现此错误?

我找到了一个解决方案fetchall(),但我担心会使用太多内存,因为SELECT.

import mysql.connector
from collections import namedtuple

con = mysql.connector.connect(host='127.0.0.1')
cursor = con.cursor(prepared=True)

user_map = {}
cursor.execute('SELECT * FROM users WHERE companyID = ?', (56, ))
Row = namedtuple('users', cursor.column_names)

for curr_row in map(Row._make, cursor.fetchall()):
    new_row = curr_row._replace(userID=None, companyID=95)

    cursor.execute('INSERT INTO users VALUES(?,?,?,?)', tuple(new_row))
    user_map[curr_row.userID] = cursor.lastrowid

cursor.close()

这有效,但速度不是很快。我在想使用fetchall()会更快,但似乎如果我不获取完整的结果集,那么 MySQL 会对我大喊大叫。

有没有办法在获取整个结果集的情况下循环遍历结果集时插入行?

4

1 回答 1

1

有没有办法在不获取整个结果集的情况下循环遍历结果集时插入行?

是的。使用两个 MySQL 连接:一个用于读取,另一个用于写入。

只要您没有数以千计的程序实例尝试连接到同一个 MySQL 服务器,性能影响就不会太糟糕。

一个连接正在读取结果集,另一个正在将行插入到同一个表的末尾,因此您不应该出现死锁。如果您用于读取表的 WHERE 条件可以显式排除您正在插入的行,如果有办法将新行与旧行区分开来,那将很有帮助。

在某种程度上,两个连接的性能影响并不重要,因为您没有太多选择。做你想做的事情的唯一另一种方法是将整个结果集啜饮到程序中的 RAM 中,关闭阅读光标,然后写入。

于 2016-12-21T17:47:07.377 回答