Solo 跨版本升级

本贴最后更新于 2062 天前,其中的信息可能已经时移世易

本文是《Solo 从设计到实现》的一个章节,该系列文章将介绍 Solo 这款 Java 博客系统是如何从无到有的,希望大家能通过它对 Solo 从设计到实现有个直观地了解、能为想参与贡献的人介绍清楚项目,也希望能为给重复发明重新定义博客系统的人做个参考 ❤️

自 Solo v3.0.0 起开始支持跨版本升级,用户直接部署最新版就可以从某个老版本进行升级,降低用户的升级成本。同时,跨版本升级机制也让大大降低了实现自动升级的难度,通过简单的脚本和 crontab 定时任务就可以实现自动升级。

升级检查

Solo 在每次启动时都会进行升级检查,调用入口在 SoloServletListener#contextInitialized 方法,实现为 UpgradeService#upgrade 方法:

/** * Upgrades if need. */ public void upgrade() { try { final JSONObject preference = optionQueryService.getPreference(); if (null == preference) { return; } final String currentVer = preference.getString(Option.ID_C_VERSION); // 数据库中的版本 if (SoloServletListener.VERSION.equals(currentVer)) { // 如果数据库中的版本和运行时版本一致则说明已经是最新版 return; } // 如果版本较老,则调用对应的升级程序进行升级,并贯穿升级下去直到最新版 switch (currentVer) { case "2.9.9": V299_300.perform(); case "3.0.0": V300_310.perform(); case "3.1.0": V310_320.perform(); case "3.2.0": V320_330.perform(); case "3.3.0": V330_340.perform(); case "3.4.0": V340_350.perform(); case "3.5.0": V350_360.perform(); case "3.6.0": V360_361.perform(); case "3.6.1": V361_362.perform(); break; default: LOGGER.log(Level.ERROR, "Please upgrade to v3.0.0 first"); System.exit(-1); } } catch (final Exception e) { LOGGER.log(Level.ERROR, "Upgrade failed, please contact the Solo developers or reports this " + "issue: https://github.com/b3log/solo/issues/new", e); System.exit(-1); } }

升级程序必须在业务逻辑开始前执行,因为 MySQL 为了保证数据一致性,有一个叫做“元数据锁”的机制,不允许表结构变更(DDL)和其他数据事务操作(DML)一起进行。

升级实现

所有版本的升级程序均放置在包 org.b3log.solo.upgrade 下,每个升级程序实现要点如下:

  • 如果需要变更表结构则进行变更
  • 如果需要迁移数据则进行迁移
  • 更新 option 中的 version 为最新版本

最简单的情况是只需升级 option 的 version,比如 v3.6.0 到 v3.6.1 的升级程序实现:

/** * Performs upgrade from v3.6.0 to v3.6.1. * * @throws Exception upgrade fails */ public static void perform() throws Exception { final String fromVer = "3.6.0"; final String toVer = "3.6.1"; LOGGER.log(Level.INFO, "Upgrading from version [" + fromVer + "] to version [" + toVer + "]...."); final BeanManager beanManager = BeanManager.getInstance(); final OptionRepository optionRepository = beanManager.getReference(OptionRepository.class); try { final Transaction transaction = optionRepository.beginTransaction(); final JSONObject versionOpt = optionRepository.get(Option.ID_C_VERSION); versionOpt.put(Option.OPTION_VALUE, toVer); optionRepository.update(Option.ID_C_VERSION, versionOpt); transaction.commit(); LOGGER.log(Level.INFO, "Upgraded from version [" + fromVer + "] to version [" + toVer + "] successfully"); } catch (final Exception e) { LOGGER.log(Level.ERROR, "Upgrade failed!", e); throw new Exception("Upgrade failed from version [" + fromVer + "] to version [" + toVer + "]"); } }

自动升级

使用 Docker 部署的话可以非常方便地实现自动升级,大致的脚本逻辑如下:

  1. docker pull b3log/solo 拉取最新镜像
  2. docker run 重启容器

我们每次发布版本都会构建好最新的 docker 镜像,用户可以通过 crontab 将升级脚本配置为定时执行来实现自动更新。升级脚本可以参考这里进行编写。

如果你使用 war 包部署要实现自动升级就稍微有点麻烦了,大致的逻辑如下:

  1. 通过社区接口检查是否有新版本 https://rhythm.b3log.org/version/solo/latest
  2. 如果有新版本则下载 war https://github.com/b3log/solo/releases
  3. 部署 war,配置文件可用脚本替换,更为简单的做法是通过环境变量 $LATKE_PROPS$LATKE_LOCAL_PROPS 来指定配置文件路径,这样就不用替换了

总之,推荐使用 Docker 进行部署,运维起来非常方便。

  • Solo

    Solo 是一款小而美的开源博客系统,专为程序员设计。Solo 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    1436 引用 • 10059 回帖 • 491 关注
  • 设计
    116 引用 • 797 回帖 • 1 关注
  • 升级
    17 引用 • 101 回帖
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的操作系统上。容器完全使用沙箱机制,几乎没有性能开销,可以很容易地在机器和数据中心中运行。

    493 引用 • 928 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • songjave via Android

    在首页的管理界面其实感觉有点突兀,作为一个博客系统,它应该是很个人化。如果谁都可以进入发表文章我感觉这样并不是很好

    1 回复
  • 88250

    其他人登录后是访客角色,不能进入后台的,除非在用户管理里改变该用户角色为普通用户。