本文是《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 部署的话可以非常方便地实现自动升级,大致的脚本逻辑如下:
docker pull b3log/solo
拉取最新镜像docker run
重启容器
我们每次发布版本都会构建好最新的 docker 镜像,用户可以通过 crontab
将升级脚本配置为定时执行来实现自动更新。升级脚本可以参考这里进行编写。
如果你使用 war 包部署要实现自动升级就稍微有点麻烦了,大致的逻辑如下:
- 通过社区接口检查是否有新版本
https://rhythm.b3log.org/version/solo/latest
- 如果有新版本则下载 war
https://github.com/b3log/solo/releases
- 部署 war,配置文件可用脚本替换,更为简单的做法是通过环境变量
$LATKE_PROPS
和$LATKE_LOCAL_PROPS
来指定配置文件路径,这样就不用替换了
总之,推荐使用 Docker 进行部署,运维起来非常方便。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于