sqlalchemy-migrate 升级降级openstack数据库

14 篇文章 0 订阅
3 篇文章 0 订阅

参考 https://sqlalchemy-migrate.readthedocs.org/en/latest/versioning.html#writing-for-a-specific-database

0.作用

可对数据库进行版本升级/降级

新版本的代码,数据库表结构发生变化。采用migrate可直接改变数据库的表结构而不影响原有的数据。

一。 SQLALchemy 迁移提供两种方式

1)api方式    migrate.versioning API

2)migrate 命令行方式

二。涉及概念

repository   : 数据库迁移所需要的配置文件、脚本等保存的目录


三。迁移的工作流程

命令行方式

1.建立repository 

[plain]  view plain copy
  1. migrate create /home/cloud/your_repository "example project"  

在创建新的repository(/home/cloud/your_repository),名为'example project'

目录下的内容

[plain]  view plain copy
  1. cloud@ubuntu22:~/your_repository$ ls -l  
  2. total 20  
  3. -rw-r--r-- 1 cloud cloud    0 五月 29 15:18 __init__.py  
  4. -rw-r--r-- 1 cloud cloud  185 五月 29 15:18 __init__.pyc  
  5. -rw-rw-r-- 1 cloud cloud  116 九月 10 17:02 manage.py  
  6. -rw-r--r-- 1 cloud cloud 1242 九月 10 17:02 migrate.cfg  
  7. -rw-r--r-- 1 cloud cloud  107 五月 29 15:18 README  
  8. drwxr-sr-x 2 cloud cloud 4096 五月 29 15:18 versions  

versions: 保存迁移所需要的各个版本脚本的目录

manage.py :  执行这个脚本跟执行migrate命令一样的效果,但是manage.py可以预设一些参数值(现在还没有设置,后面会说明)



migrate.cfg: 配置文件

repository_id : 上面命令行定义的name

version_table: 数据库记录migrate版本的表名

2.建立版本控制(即说明要迁移的数据库名,并且将所需信息写入数据库)

[plain]  view plain copy
  1. python /home/cloud/your_repository/manage.py version_control sqlite:///test.db  /home/cloud/your_repository/  
将数据库与repository建立关联关系,会在test.db创建新表migrate_version,版本为0


查看当前版本

[python]  view plain copy
  1. python /home/cloud/your_repository/manage.py db_version sqlite:///test.db your_repository/  
  2. >>0  
3.给manage.py添加预设参数

使用manage.py的预设参数,省去每次执行命令都带上数据库信息以及repository信息

[python]  view plain copy
  1. migrate manage manage.py --repository=/home/cloud/your_repository --url=sqlite:///test.db  
设置repository 以及url,  看下manage.py文件的改变

新添了url以及repository的值

查看当前版本

[python]  view plain copy
  1. python /home/cloud/your_repository/manage.py db_version  
  2. >>0  

4.添加版本脚本(版本1,添加新表account)

[python]  view plain copy
  1. python /home/cloud/your_repository/manage.py script "add account table"  
在versions目录,多了文件001_add_account_table.py


编辑001_add_account_table.py,

upgrade() 更新数据库到该新版本,需要包含有对数据库schema的更新

downgrade() 回滚upgrade做的操作。

这里upgrade()方法创建新表account,downgrade方法删除表account

[python]  view plain copy
  1. from sqlalchemy import Table, Column, Integer, String, MetaData  
  2.   
  3. meta = MetaData()  
  4.   
  5. account = Table(  
  6.     'account', meta,  
  7.     Column('id', Integer, primary_key=True),  
  8.     Column('login', String(40)),  
  9.     Column('passwd', String(40)),  
  10. )  
  11.   
  12.   
  13. def upgrade(migrate_engine):  
  14.     meta.bind = migrate_engine  
  15.     account.create()  
  16.   
  17.   
  18. def downgrade(migrate_engine):  
  19.     meta.bind = migrate_engine  
  20.     account.drop()  

5.测试脚本

执行版本升级前,测试脚本是否有语法错误

[python]  view plain copy
  1. python /home/cloud/your_repository/manage.py test  
  2. >>Upgrading...  
  3. done  
  4. Downgrading...  
  5. done  
  6. Success  
6.升级数据库到新版本

[python]  view plain copy
  1. python /home/cloud/your_repository/manage.py upgrade  
  2. >>0 -> 1...   
  3. done  

添加了新表account,以及更新数据库表migrate_version,版本变为1


7.修改已存在的表

给表account添加新属性email

[python]  view plain copy
  1. python /home/cloud/your_repository/manage.py script 'add email column'  
编辑文件 002_add_email_column.py
[python]  view plain copy
  1. from sqlalchemy import Table, MetaData, String, Column  
  2.   
  3.   
  4. def upgrade(migrate_engine):  
  5.     meta = MetaData(bind=migrate_engine)  
  6.     account = Table('account', meta, autoload=True)  
  7.     emailc = Column('email', String(128))  
  8.     emailc.create(account)  
  9.   
  10.   
  11. def downgrade(migrate_engine):  
  12.     meta = MetaData(bind=migrate_engine)  
  13.     account = Table('account', meta, autoload=True)  
  14.     account.c.email.drop()  

执行升级操作

[python]  view plain copy
  1. python /home/cloud/your_repository/manage.py upgrade  
  2. >>1 -> 2...   
  3. done  
观察数据库test.db表account的变化,添加了新属性email


8.数据库降级

[python]  view plain copy
  1. python /home/cloud/your_repository/manage.py db_version  
  2. >>2  
  3. python /home/cloud/your_repository/manage.py downgrade 1  
  4. >>2 -> 1...   
  5. done  
  6. python /home/cloud/your_repository/manage.py db_version  
  7. >>1  
观察数据库test.db表account的变化,属性email被删除

9.其它migrate命令

migrate -h

migrate -h db_version

api方式

参考https://sqlalchemy-migrate.readthedocs.org/en/latest/api.html#module-migrate.versioning.api

migrate.versioning.api 函数与migrate命令是相互对应。

如migrate.versioning.api.upgrade  对应migrate upgrade

实现过程 

1.仿照your_repository建立新目录/home/cloud/my_repository及目录下的文件

manage.py

[python]  view plain copy
  1. #!/usr/bin/env python  
  2. from migrate.versioning.shell import main  
  3.   
  4. if __name__ == '__main__':  
  5.     main(debug='False', repository='.')  
  6.     #main(url='sqlite:///project.db', debug='False', repository='my_repository')  

migrate.cfg

[python]  view plain copy
  1. [db_settings]  
  2. # Used to identify which repository this database is versioned under.  
  3. # You can use the name of your project.  
  4. repository_id=example_project  
  5.   
  6. # The name of the database table used to track the schema version.  
  7. # This name shouldn't already be used by your project.  
  8. # If this is changed once a database is under version control, you'll need to   
  9. # change the table name in each database too.   
  10. version_table=migrate_version  
  11.   
  12. # When committing a change script, Migrate will attempt to generate the   
  13. # sql for all supported databases; normally, if one of them fails - probably  
  14. # because you don't have that database installed - it is ignored and the   
  15. # commit continues, perhaps ending successfully.   
  16. # Databases in this list MUST compile successfully during a commit, or the   
  17. # entire commit will fail. List the databases your application will actually   
  18. # be using to ensure your updates to that database work properly.  
  19. # This must be a list; example: ['postgres','sqlite']  
  20. required_dbs=[]  
  21.   
  22. # When creating new change scripts, Migrate will stamp the new script with  
  23. # a version number. By default this is latest_version + 1. You can set this  
  24. # to 'true' to tell Migrate to use the UTC timestamp instead.  
  25. use_timestamp_numbering=False  

/my_repository/versions/001_Add_account_table.py

[python]  view plain copy
  1. from sqlalchemy import Column,MetaData,Integer,String,Table  
  2. from migrate import *  
  3.   
  4. meta = MetaData()  
  5.   
  6. account = Table(  
  7.     'account', meta,  
  8.     Column('id', Integer, primary_key=True),  
  9.     Column('login', String(40)),  
  10.     Column('passwd', String(40)),  
  11. )  
  12.   
  13. def upgrade(migrate_engine):  
  14.     # Upgrade operations go here. Don't create your own engine; bind  
  15.     # migrate_engine to your metadata  
  16.     #meta =MetaData()  
  17.     meta.bind = migrate_engine  
  18.       
  19.     #account = Table(  
  20.     #    'account',meta,  
  21.     #     Column('id', Integer, primary_key=True),  
  22.     #     Column('login', String(40)) )  
  23.     try:  
  24.         account.create()  
  25.     except:  
  26.         pass  
/my_repository/versions/002_add_email_colun.py

[python]  view plain copy
  1. from sqlalchemy import Table, MetaData, String,Column  
  2. from migrate import *  
  3.   
  4.   
  5. def upgrade(migrate_engine):  
  6.     # Upgrade operations go here. Don't create your own engine; bind  
  7.     # migrate_engine to your metadata  
  8.     meta = MetaData()  
  9.     meta.bind = migrate_engine  
  10.     account = Table('account', meta, autoload=True)  
  11.     emailc = Column('email', String(128))  
  12.     emailc.create(account)  
  13.   
  14.   
  15. def downgrade(migrate_engine):  
  16.     # Operations to reverse the above upgrade go here.  
  17.     meta = MetaData(bind=migrate_engine)  
  18.     account = Table('account', meta, autoload=True)  
  19.     account.c.email.drop()  

2.编写db迁移程序migrate.py

参考openstack cinder-manager   db sync

[python]  view plain copy
  1. from migrate.versioning import api as versioning_api  
  2. import sqlalchemy  
  3.   
  4. _ENGINE = None  
  5.   
  6. def get_engine():  
  7.     global _ENGINE  
  8.     if _ENGINE:  
  9.         return _ENGINE  
  10.   
  11.     sql_connection = "sqlite:home/cloud/project.db"  
  12.   
  13.     engine_args = {  
  14.                     "pool_recycle"3600,  
  15.                     "echo"False  
  16.                     }  
  17.   
  18.     _ENGINE = sqlalchemy.create_engine(sql_connection, **engine_args)  
  19.   
  20.     _ENGINE.connect()  
  21.     return _ENGINE  
  22.   
  23. def get_repository():  
  24.     repository_path = "/home/cloud/my_repository"  
  25.     return repository_path  
  26.   
  27. def db_version():  
  28.     repository = get_repository()  
  29.     try:  
  30.         return versioning_api.db_version(get_engine(), repository)  
  31.     except :  
  32.         # if we aren't version controlled we may already have the database  
  33.         # in the state from before we started version control, check for that  
  34.         # and set up version_control appropriately  
  35.         meta = sqlalchemy.MetaData()  
  36.         engine = get_engine()  
  37.         meta.bind = engine  
  38.         tables = meta.tables  
  39.         if len(tables) == 0:  
  40.             db_version_control(000)  
  41.             return versioning_api.db_version(get_engine(), repository)  
  42.         else:  
  43.             #db has tables without migrate_version, it out of control  
  44.             raise  
  45. def db_version_control(version=None):  
  46.     repository = get_repository()  
  47.     versioning_api.version_control(get_engine(), repository, version)  
  48.   
  49. def migrate_db(version=None):  
  50.     if version is not None:  
  51.         try:  
  52.             version = int(version)  
  53.         except ValueError as exception:  
  54.             raise exception  
  55.   
  56.     #get current version  
  57.     current_version = db_version()  
  58.   
  59.     repository = get_repository()  
  60.     if version is None or version > current_version:  
  61.         return versioning_api.upgrade(get_engine(), repository, version)  
  62.     else:  
  63.         return versioning_api.downgrade(get_engine(), repository, version)  
  64.   
  65. if __name__ == "__main__":  
  66.     migrate_db()  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值