使用SQLObject将数据从一个sqlite数据库迁移到多个SQLite数据库

时间:2011-11-26 18:15:19

标签: python sqlite migration sqlobject

到目前为止,我们的应用程序一直使用一个SQLite数据库和SQLObject作为ORM。显然,在某些时候我们知道我们必须面对SQLite并发问题,所以我们做到了。

我们最终将当前数据库拆分为多个数据库。这意味着每个表模式保持不变,但我们将不同的表分布到多个数据库中,从而将紧密耦合的表保持在一起。

现在这在我们的应用程序的新版本的干净安装中非常有效,但是在我们的应用程序开始工作之前,升级到我们的应用程序的先前版本到这个新版本需要特殊的数据迁移。在这种情况下,数据库迁移很简单,将表从这个单独的数据库移动到适当的不同数据库中。

举例来说,请考虑这是较旧的结构:

single_db.db ---单个数据库

 * A -- Table A
 * B -- Table B
 * C -- Table C
 * D -- Table D
 * E -- Table E
 * F -- Table F

新结构:

db1.db ---数据库1

 - A -- Table A
 - B -- Table B
 - C -- Table C
 - D -- Table D

db2.db ---数据库2

 - E -- Table E

db3.db ---数据库3

 - F -- Table F

当升级发生时,我们的应用程序将使用上述3个数据库创建新结构,并在其中包含空表。此外,包含所有表和实际数据的旧数据库single_db.db也将存在。现在,在我们的应用程序开始工作之前,它应该移动表,或者我应该说将数据从旧数据库中的表复制到相应新数据库中的相应表。

我需要编写此数据库迁移的代码。我知道我可以使用旧的数据库连接查询表,并使用较新的数据库连接将返回的行插入到相应的表中。我要提到的一个警告是这些表中的一些可以包含大量行。这就是2/3表中的行数可以达到2到250万。

所以想问我是否可以使用任何其他SLQObject技巧,因为我在SQLite之上使用SQLObject并且之前有人这样做过吗?

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

我意识到你现在可能已经解决了这个问题,但对于任何使用谷歌搜索的人来说,我必须做的几乎与OP完全相同,这是我使用的代码的核心部分(它是从我找到的东西修改过来的,但我可以'再找一遍归功于原作者,道歉!)

def _iterdump(connection, table_name):
    """
    Returns an iterator to dump a database table in SQL text format.
    """

    cu = connection.cursor()

    yield('BEGIN TRANSACTION;')

    # sqlite_master table contains the SQL CREATE statements for the database.
    q = """
       SELECT name, type, sql
        FROM sqlite_master
            WHERE sql NOT NULL AND
            type == 'table' AND
            name == :table_name
        """
    schema_res = cu.execute(q, {'table_name': table_name})
    for table_name, type, sql in schema_res.fetchall():
        if table_name == 'sqlite_sequence':
            yield('DELETE FROM sqlite_sequence;')
        elif table_name == 'sqlite_stat1':
            yield('ANALYZE sqlite_master;')
        elif table_name.startswith('sqlite_'):
            continue
        else:
            yield('%s;' % sql)

        # Build the insert statement for each row of the current table
        res = cu.execute("PRAGMA table_info('%s')" % table_name)
        column_names = [str(table_info[1]) for table_info in res.fetchall()]
        q = "SELECT 'INSERT INTO \"%(tbl_name)s\" VALUES("
        q += ",".join(["'||quote(" + col + ")||'" for col in column_names])
        q += ")' FROM '%(tbl_name)s'"
        query_res = cu.execute(q % {'tbl_name': table_name})
        for row in query_res:
            yield("%s;" % row[0])

如果传递原始数据库的sqlite连接和原始数据库中表的名称,则此生成器将返回可以传递给新数据库的sqlite对象执行的命令。

当我这样做时,我还在所有表上首先计算了行数,并在执行INSERT行时递增了计数器,以便我可以显示迁移的进度。