序列如下。假设我要合并a.db和b.db.在命令行中,我执行以下操作。
它运作良好,但在引用的网站中,提问者询问加速,答案是使用'begin'和'commit'命令。
然后,我想出了以下python代码来完成同样的事情。我用SQLiteDB抽象SQLite函数调用,其中一个方法是runCommand()。即使我删除了self.connector.commit(),我也得到了同样的错误。
# run command
def runCommand(self, command):
self.cursor.execute(command)
self.connector.commit() # same error even though I delete this line
db = SQLiteDB('a.db')
cmd = "attach \"%s\" as toMerge" % "b.db"
print cmd
db.runCommand(cmd)
cmd = "begin"
db.runCommand(cmd)
cmd = "insert into benchmark select * from toMerge.benchmark"
db.runCommand(cmd)
cmd = "commit"
db.runCommand(cmd)
cmd = "detach database toMerge"
db.runCommand(cmd)
但是,我收到了以下错误。
OperationalError: cannot commit - no transaction is active
即使出错,结果db也很好地合并了。没有开始/提交,根本就没有错误。
答案 0 :(得分:12)
显然,Cursor.execute
不支持'commit'命令。它确实支持'begin'命令,但这是多余的,因为sqlite3会为你开始它们:
>>> import sqlite3
>>> conn = sqlite3.connect(':memory:')
>>> cur = conn.cursor()
>>> cur.execute('begin')
<sqlite3.Cursor object at 0x0104B020>
>>> cur.execute('CREATE TABLE test (id INTEGER)')
<sqlite3.Cursor object at 0x0104B020>
>>> cur.execute('INSERT INTO test VALUES (1)')
<sqlite3.Cursor object at 0x0104B020>
>>> cur.execute('commit')
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
cur.execute('commit')
OperationalError: cannot commit - no transaction is active
>>>
只需在commit
对象上使用Connection
方法。
至于你的第二个问题,在合并文件时调用begin / commit并不是绝对必要的:只要确保没有磁盘错误,对数据库的修改或者以错误的方式查看计算机的人正在发生。所以开始/提交可能是一个好主意。当然,如果原始的数据库没有被修改(我老实说没有看过),那么就没有必要。如果出现错误,您可以废弃部分输出并重新开始。
它还提供了加速,因为每次更改都不必在发生时写入磁盘。它们可以存储在内存中并批量写入。但正如所提到的sqlite3
为您处理这个问题。
另外,值得一提的是
cmd = "attach \"%s\" as toMerge" % "b.db"
是错误的,因为它被剥夺了。如果你想正确地做错事,那就是
cmd = 'attach "{0}" as toMerge'.format("b.db") #why not just one string though?
这与新版本的python向前兼容,这将使移植代码更容易。
如果你想做正确的事情,那就是
cmd = "attach ? as toMerge"
cursor.execute(cmd, ('b.db', ))
这样可以避免sql注入,显然会稍快一些,所以它是双赢的。
您可以按如下方式修改runCommand
方法:
def runCommand(self, sql, params=(), commit=True):
self.cursor.execute(sql, params)
if commit:
self.connector.commit()
现在,当您不需要提交时,通过传递commit=False
,您无法在每个命令之后提交。这保留了交易的概念。