在数据库中存储版本号

问题#

单纯的在数据库中存储版本号只需要一个字符串字段就可以了,难点是如何对版本号字段进行排序。 简单对字符串排序会导致错误的结果,例如:“4.2.2”会大于“4.2.16” 如果版本号是受控的,那么可以规定版本号的规则,处理起来比较容易一些。 若要设计一个通用系统,可以存储各种软件的版本号,问题会更加复杂。 软件的版本号通常遵循一个通用的规则:“{Major}.{Minor}.{Revsion}”,但也有的会在版本号后面加上一些修饰,例如:“5.10.12-alpha-2”。

解决方案#

查询时转换#

在查询时将版本号转换成可排序的形式:

SELECT * FROM Requirements
ORDER BY string_to_array(version, '.')::int[];

优点:不改变存储的形式,在数据库中存储原始的版本号,可读性好。

缺点:在数据量大的时候性能比较差,尤其在大数据场景下无法使用这个方案。

参考资料:https://newbedev.com/sql-sort-by-version-number-a-string-of-varying-length

将版本号分段存储到不同的字段中#

优点:在保留可读性的同时,支持高效的排序操作。

缺点:字段较多,操作数据的Sql比较麻烦。

将版本号转换成可排序的形式存储#

比较有技巧性的方案,主要思想是把版本号各个部分设置一个最大长度,补全后连接到一起变成一个值。

例如:设每个部分最大为5位

“4.2.2” 转换为“000040000200002”

“4.2.16”转换为“000040000200016”

也可以保留原样用空格补齐:https://stackoverflow.com/a/8730277/775640

“4.2.2” 转换为“ 4. 2. 2”

“4.2.16”转换为“ 4. 2. 16”

以上两种都是将版本号转换后还是以字符串形式存储,如果转换成以数值形式存储的话占用空间更少,查询效率会更高一些。

例如:

“4.2.2” 转换为“4.0000200002”

“4.2.16”转换为“4.0000200016”

通过将版本号后面的部分补齐放到小数点后,可以支持扩展,例如:“4.2.2”和“4.2.2.1”可以放在一起对比。具体可以参考:https://stackoverflow.com/a/66238047/775640

需要注意的是,将版本号转换成数字后位数较多,需要使用Decimal类型存储,以确保位数和精度

修饰符怎么处理?

如上所述,有些版本号后面还会增加修饰,例如:“5.10.12-alpha-2”。

如果将版本号以字符串形式存储,则在转换时可以简单的将修饰存储进去,如:“5.10.12-alpha-2"转换为“000050001000012alpha-2”。

如果是转换成数值形式存储,也可以将常见的修饰符也编码成数值,这里有一个比较完善的实现:https://stackoverflow.com/a/50181582/775640

我认为全部转换成数值是比较理想的方案。

另外在分段补全时也不必每一位都补全到相同的位数,主版本号,次版本号通常不会太大,可以预留4位数,后面的修订号可以增加到6位。

其它相关资料#

语义化版本#

目前很多系统都使用语义化版本,语义化版本中非常重要的是定义了兼容和不兼容的升级时,版本号应该如何变化。 现代系统经常会使用很多开源组件,组件间还有相互的依赖,语义化版本对于帮助确定各个组件的最佳版本有很大的作用。

语义化版本说明:https://semver.org/lang/zh-CN/

日历化版本#

有时候定义一个复杂的版本规则可能没有必要,直接用日期时间做为版本也是一种做法。

日历化版本说明:https://calver.org/overview%5Fzhcn.html

Version类#

Java9新增了一个Version类,可以用来描述版本:https://docs.oracle.com/javase/9/docs/api/java/lang/module/ModuleDescriptor.Version.html

comments powered by Disqus