侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

Openstack 使用migrate进行数据库升级实现方案详细介绍

数据库  /  管理员 发布于 6年前   179

Openstack 使用migrate进行数据库升级实现方案详细介绍

OpenStack中随着版本的切换,新版本加入一些数据库表或者增加字段等是必然的事情,如何比较容易的进行这些数据库升级的适配和管理,这里就要用到oslo_db中的migrate了,这里以为M版本的heat为例,讲解一下migrate管理db的原理。

我们使用migrate需要用到的主要包含以下两部分:1.versions里面的为版本号+数据库适配脚本;2.migrate.cfg为migrate需要用到的配置文件,两部分的命名是固定的。


使用migrate进行数据库升级非常简单,heat这边提供了heat-manage db_sync, db_version的命令用来升级db以及查看当前db的版本号,这里以执行heat-manages db_sync,看下migrate的过程。

def db_sync(engine, version=None):   path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'migrate_repo')   return oslo_migration.db_sync(engine, path, version,      init_version=INIT_VERSION) 

heat代码的入口在这里,需要传入engine用来连接db,version为我们需要升级到的版本,这里没有传,可以看到heat这边是直接使用oslo_migrate的db_sync方法,我们看下三方库中的这个方法。

def db_sync(engine, abs_path, version=None, init_version=0, sanity_check=True):   """Upgrade or downgrade a database.    Function runs the upgrade() or downgrade() functions in change scripts.    :param engine:    SQLAlchemy engine instance for a given database   //连接数据库   :param abs_path:   Absolute path to migrate repository.         //migrate仓库的绝对路径   :param version:   Database will upgrade/downgrade until this version. //需要升级或者降级到的版本号,如果不传则默认升级到最新版本  If None - database will update to the latest  available version.   :param init_version: Initial database version   //数据库的初始版本号,会以该初始版本为起点升级   :param sanity_check: Require schema sanity checking for all tables    //合理性检查   """    if version is not None:     try:       version = int(version)     except ValueError:       raise exception.DBMigrationError(_("version should be an integer"))    current_version = db_version(engine, abs_path, init_version)   repository = _find_migrate_repo(abs_path)   if sanity_check:     _db_schema_sanity_check(engine)   if version is None or version > current_version:     migration = versioning_api.upgrade(engine, repository, version)   else:     migration = versioning_api.downgrade(engine, repository,version)   if sanity_check:     _db_schema_sanity_check(engine)    return migration 

代码很清晰,简洁。可以看到,整个过程就是先查询下当前db的版本,然后声明一个migrate仓库示例,对db做合理性检查(主要是针对mysql),然后根据传入的version和当前的version决定是升级或者降低,最后再次检查,整个migrate就完成了。

首先是查询当前数据库的版本,

def db_version(engine, abs_path, init_version):   """Show the current version of the repository.    :param engine: SQLAlchemy engine instance for a given database   :param abs_path: Absolute path to migrate repository   :param init_version: Initial database version   """   repository = _find_migrate_repo(abs_path)   try:     return versioning_api.db_version(engine, repository)   except versioning_exceptions.DatabaseNotControlledError:     meta = sqlalchemy.MetaData()     meta.reflect(bind=engine)     tables = meta.tables     if len(tables) == 0 or 'alembic_version' in tables:       db_version_control(engine, abs_path, version=init_version)       return versioning_api.db_version(engine, repository)     else:       raise exception.DBMigrationError(         _("The database is not under version control, but has "          "tables. Please stamp the current version of the schema "          "manually.")) 

首先是根据传入的绝对路径,构造一个仓库对象的示例,这里比较关键,初始化方法如下,可以看到我们前面提到migrate.cfg和versions就是在这里被使用的,而且名字也是固定的,必须为migrate.cfg和versions。

class Repository(pathed.Pathed):   """A project's change script repository"""    _config = 'migrate.cfg'   _versions = 'versions'    def __init__(self, path):     log.debug('Loading repository %s...' % path)     self.verify(path)     super(Repository, self).__init__(path)     self.config = cfgparse.Config(os.path.join(self.path, self._config))     self.versions = version.Collection(os.path.join(self.path,    self._versions))     log.debug('Repository %s loaded successfully' % path)     log.debug('Config: %r' % self.config.to_dict()) 

这里会验证我们传入的path下面是否存在versions和migrate.cfg,因此我们的代码目录结构也必须按照这个放。self.config主要是用来管理migrate.cfg的配置,self.versions主要用来管理如何升级,repository对象另外还包含3个比较重要的属性,latest:最新的版本(versions中版本号最大的),这里是73,version_table:用来记录和管理migrate版本号的数据库表,这里是migrate_version,id用来存放我们管理的数据库标示,这里是heat,后两项都是从数据库里面取。

@property   def latest(self):     """API to :attr:`migrate.versioning.version.Collection.latest`"""     return self.versions.latest    @property   def version_table(self):     """Returns version_table name specified in config"""     return self.config.get('db_settings', 'version_table')    @property   def id(self):     """Returns repository id specified in config"""     return self.config.get('db_settings', 'repository_id') 

回到之前的代码

try:   return versioning_api.db_version(engine, repository) except versioning_exceptions.DatabaseNotControlledError:   meta = sqlalchemy.MetaData()   meta.reflect(bind=engine)   tables = meta.tables   if len(tables) == 0 or 'alembic_version' in tables:     db_version_control(engine, abs_path, version=init_version)     return versioning_api.db_version(engine, repository)   else:     raise exception.DBMigrationError(       _("The database is not under version control, but has "        "tables. Please stamp the current version of the schema "        "manually.")) 

这里会根据数据库引擎和刚才的repository实例对象获取当前数据库的版本号,其实就是从migrate本身所在数据表中去查找当前的版本号(version_version),假如是第一次使用migrate,由于还没有建立migrate_version表,所以引发异常。这里会去查一下当前数据库中的所有数据表,如果已有其他数据库表,则会引发DBMigrationError的异常,因为migrate必须在建立其他数据表之前先建立才能管控所有的数据表,假如我们之前没有使用migrate机制但是想在后面的db控制中使用起来,这里有2个思路:手动插入migrate_version数据表并配置合适的版本或者手动插入alebic_version。

继续往下面看,如果是第一次使用migrate,

db_version_control(engine, abs_path, version=init_version) 

会建立migrate_version,并设置合适的初始值,也就是传入的init_version,后续的数据库升级等操作就可以通过migrate管控起来了。migrate_version表建立起来后,就回到了最初的流程,根据我们db_sync传入的版本号和当前的版本号,migrate会执行versions里面每个版本的upgrade()方法直至升级完成并更新migrate_version中的版本号。

  使用migrate的好处在于,可以很方便的集中记录和管理每次对数据库的变动,在后续升级过程中,一键式完成对应的适配操作,非常方便,并且不会出现重复增加字段等操作,在开发过程中,我们只要知道了migrate的原理,就能很方便的使用起来了。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


  • 上一条:
    shell 命令行中操作HBase数据库实例详解
    下一条:
    MySql带OR关键字的多条件查询语句
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 分库分表的目的、优缺点及具体实现方式介绍(0个评论)
    • DevDB - 在 VS 代码中直接访问数据库(0个评论)
    • 在ubuntu系统中实现mysql数据存储目录迁移流程步骤(0个评论)
    • 在mysql中使用存储过程批量新增测试数据流程步骤(0个评论)
    • php+mysql数据库批量根据条件快速更新、连表更新sql实现(0个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2017-06
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-01
    • 2018-05
    • 2018-10
    • 2018-11
    • 2020-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-09
    • 2021-02
    • 2021-04
    • 2021-07
    • 2021-08
    • 2021-11
    • 2021-12
    • 2022-02
    • 2022-03
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-07
    • 2023-08
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-03
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客