代码之家  ›  专栏  ›  技术社区  ›  prosseek

将SQLite文件合并到一个db文件中,以及“开始/提交”问题

  •  5
  • prosseek  · 技术社区  · 14 年前

    This post 指的是这个 page 用于合并SQLite数据库。

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

    • 附上“b.db”作为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)
    

    但是,我有以下错误。

    OperationalError: cannot commit - no transaction is active
    

    即使出现错误,结果db也很好地合并了。如果没有begin/commit,就不会有任何错误。

    • 是否必须运行begin/commit来安全地合并db文件?帖子说begin/commit的目的是为了加速。那么,使用begin/commit命令和不使用begin/commit命令在加速方面有什么区别呢?
    1 回复  |  直到 7 年前
        1
  •  12
  •   aaronasterling    14 年前

    显然地, 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 对象。

    它还提供了一个加速,因为每次更改都不必在发生时写入磁盘。它们可以存储在内存中,也可以批量写入。但如前所述 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