Python 数据库更改与软件更新

Python 数据库更改与软件更新,python,sqlite,Python,Sqlite,我有一个程序,它有一个具有特定模式的数据库,v0.1.0 在我的下一个版本(v0.1.1)中,我对数据库模式进行了更改 因此,当我更新到(0.1.1)时,我希望这些更改在不影响(0.1.0)及其后续版本中的原始数据的情况下生效 如何进行更改而不影响(0.1.0)数据库数据并在后续版本中跟踪这些更改 我将python与sqlite3一起使用 更新 不支持该软件的多个版本。数据库依赖于您正在使用的verion 没有对数据库的并发访问,每个版本1个数据库 因此,用户可以使用旧版本,但当他们升级到新版本

我有一个程序,它有一个具有特定模式的数据库,
v0.1.0

在我的下一个版本(
v0.1.1
)中,我对数据库模式进行了更改

因此,当我更新到(
0.1.1
)时,我希望这些更改在不影响(
0.1.0
)及其后续版本中的原始数据的情况下生效

如何进行更改而不影响(
0.1.0
)数据库数据并在后续版本中跟踪这些更改

我将python与
sqlite3
一起使用

更新

不支持该软件的多个版本。数据库依赖于您正在使用的verion

没有对数据库的并发访问,每个版本1个数据库


因此,用户可以使用旧版本,但当他们升级到新版本时,.sqlite模式将被更改。

长期来看,您最好使用ORM,例如迁移工具。

有几种方法可以做到这一点,我只提一种

看起来您已经在数据库中跟踪了该版本。在应用程序启动时,您需要对照正在运行的应用程序的版本检查此版本,并运行任何将执行架构更改的sql脚本

更新

这方面的一个例子是:

import os
import sqlite3 as sqlite

def make_movie_table(cursor):
    cursor.execute('CREATE TABLE movies(id INTEGER PRIMARY KEY, title VARCHAR(20), link VARCHAR(20))')

def make_series_table(cursor):
     cursor.execute('CREATE TABLE series(title VARCHAR(30) PRIMARY KEY,series_link VARCHAR(60),number_of_episodes INTEGER,number_of_seasons INTEGER)')

def make_episode_table(cursor):
    cursor.execute('CREATE TABLE episodes(id INTEGER PRIMARY KEY,title VARCHAR(30),episode_name VARCHAR(15), episode_link VARCHAR(40), Date TIMESTAMP, FOREIGN KEY (title) REFERENCES series(title) ON DELETE CASCADE)')

def make_version_table(cursor):
    cursor.execute('CREATE TABLE schema_versions(version VARCHAR(6))')
    cursor.execute('insert into schema_versions(version) values ("0.1.0")')

def create_database(sqlite_file):
    if not os.path.exists(sqlite_file):
        connection = sqlite.connect(sqlite_file)
        cursor = connection.cursor()
        cursor.execute("PRAGMA foreign_keys = ON")
        make_movie_table(cursor)
        make_series_table(cursor)
        make_episode_table(cursor)
        make_version_table(cursor)
        connection.commit()
        connection.close()

def upgrade_database(sqlite_file):
    if os.path.exists(sqlite_file):
        connection = sqlite.connect(sqlite_file)
        cursor = connection.cursor()

        cursor.execute("select max(version) from schema_versions")
        row = cursor.fetchone()
        database_version = row[0]
        print('current version is %s' % database_version)

        if database_version == '0.1.0':
            print('upgrading version to 0.1.1')
            cursor.execute('alter table series ADD COLUMN new_column1 VARCHAR(10)')
            cursor.execute('alter table series ADD COLUMN new_column2 INTEGER')
            cursor.execute('insert into schema_versions(version) values ("0.1.1")')

        #if database_version == '0.1.1':
            #print('upgrading version to 0.1.2')
            #etc cetera

        connection.commit()
        connection.close()

#I need to add 2 columns to the series table, when the user upgrade the software.

if __name__ == '__main__':
    create_database('/tmp/db.sqlite')
    upgrade_database('/tmp/db.sqlite')
每个升级脚本都会处理,然后将数据库中的版本更新为最新版本。请注意,我们不使用
elif
语句,这是为了在需要时可以通过多个版本升级数据库

有一些警告需要注意:

  • 运行升级时,您将希望在出现任何错误时回滚,以避免使数据库处于不可用状态。-更新如前所述,这是不正确的,谢谢Martijn
  • 如果可以避免重命名和列删除,如果必须,请确保使用它们的任何视图也已更新

使用跟踪数据库中的架构版本,并保留一系列升级步骤:

def get_schema_version(conn):
    cursor = conn.execute('PRAGMA user_version')
    return cursor.fetchone()[0]

def set_schema_version(conn, version):
    conn.execute('PRAGMA user_version={:d}'.format(version))

def initial_schema(conn):
    # install initial schema
    # ...

def ugrade_1_2(conn):
    # modify schema, alter data, etc.

# map target schema version to upgrade step from previous version
upgrade_steps = {
    1: initial_schema,
    2: ugrade_1_2,
}

def check_upgrade(conn):
    current = get_schema_version(conn)
    target = max(upgrade_steps)
    for step in range(current + 1, target + 1):
        if step in upgrade_steps:
            upgrade_steps[step](conn)
            set_schema_version(conn, step)

您是否使用ORM或任何其他数据库抽象?旁注:使用并使不向后兼容的数据库架构更改成为主要版本更改。您的软件是否有多个版本同时读取同一数据库?或者你只是想支持降级?例如,您有一个数据库文件,并且您的软件版本1需要能够继续访问数据,即使版本2在同一文件中使用了较新的架构?如果您手动构建了架构,则必须手动编写迁移脚本。理想情况下,这只是创建新表/视图/索引/键,更改表以添加具有默认值的新列,并替换视图;否则,您可能还需要转储所有数据(通过临时表、另一个db、一些其他持久性格式等)。当然,您需要为模式的每个活动版本维护更新脚本,以便可以将0.1.0更新为0.1.3(无论是在1步还是3步中).我认为OP有多个客户端从同一个数据库文件读取数据;Alembic无法解决让多个版本读取具有更改模式的文件的问题。因此,您发布了一个仅链接的答案(),甚至没有回答手头的问题。巨大的资源,但是OP的问题呢?@lix;我大体上同意链接腐烂,但我提出了一些技术(ORMs和迁移工具),并提供了示例链接。我向OP明确表示,有一些普遍接受的技术可以解决他们的问题。我的帖子对断开的链接仍然有价值,我并没有简单地推迟回答。@而且-我可以看到,但是,从你的答案中去掉链接,你列出的只是两个没有任何引用或示例的名字。当然这是有用的信息,但也不一定是答案。我觉得这应该是一个很好的评论,但仍然不是一个真正的答案。请注意,
sqlite3
bindings。谢谢,这似乎就是我想要的。我的数据库更改都是更改。