将SQLite文件合并到一个db文件中,然后"开始/提交"问题

pro*_*eek 5 python sqlite merge

这篇文章引用了这个用于合并SQLite数据库的页面.

顺序如下.假设我要合并a.db和b.db. 在命令行中,我执行以下操作.

  • sqlite3 a.db
  • 将'b.db'附加到M;
  • 开始; < -
  • 插入基准select*from toM.benchmark;
  • 承诺; < -
  • 分离数据库toM;

它运作良好,但在引用的网站中,提问者询问加速,答案是使用'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)
Run Code Online (Sandbox Code Playgroud)

但是,我收到以下错误.

OperationalError: cannot commit - no transaction is active
Run Code Online (Sandbox Code Playgroud)

即使错误,结果db也很好地合并.没有开始/提交,根本就没有错误.

  • 为什么我不能运行begin/commit命令?
  • 是否绝对有必要运行begin/commit来安全地合并db文件?帖子说开始/提交的目的是为了加速.那么,就加速而言,使用和不使用begin/commit命令有什么区别?

aar*_*ing 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
>>> 
Run Code Online (Sandbox Code Playgroud)

只需commitConnection对象上使用该方法即可.

至于你的第二个问题,在合并文件时调用begin/commit并不是绝对必要的:只要确保没有磁盘错误,对数据库的修改或在计算机发生错误的情况下查看计算机的人.所以开始/提交可能是一个好主意.当然,如果原始的数据库没有被修改(我老实说没有看过),那么就没有必要.如果出现错误,您可以废弃部分输出并重新开始.

它还提供了加速,因为每次更改都不必在发生时写入磁盘.它们可以存储在内存中并批量写入.但正如上面提到的那样sqlite3.

此外,值得一提的是

cmd = "attach \"%s\" as toMerge" % "b.db"
Run Code Online (Sandbox Code Playgroud)

在它被剥夺的意义上是错误的.如果你想正确地做错事,那就是

cmd = 'attach "{0}" as toMerge'.format("b.db") #why not just one string though?
Run Code Online (Sandbox Code Playgroud)

这与新版本的python向前兼容,这将使移植代码更容易.

如果你想做正确的事,那就是

cmd = "attach ? as toMerge"
cursor.execute(cmd, ('b.db', ))
Run Code Online (Sandbox Code Playgroud)

这避免了sql注入,显然,稍微快一点,所以它是双赢的.

您可以runCommand按如下方式修改方法:

def runCommand(self, sql, params=(), commit=True):
    self.cursor.execute(sql, params)
    if commit:
        self.connector.commit()
Run Code Online (Sandbox Code Playgroud)

现在,commit=False当您不需要提交时,通过传递,您无法在每个命令之后提交.这保留了交易的概念.