China
  • 021-57675563

当前位置:知识中心 / 轩田技术篇 /

技术干货 | 数据库移植 - 动手

发布时间:2023-09-15    浏览人数:1人查看

数据库移植的第一步就是准备,说实话从决定要做到真正动手,是需要做很多心里建设的。


我们这次要面对的是一个庞大的系统,不是一个人花几个月就开发出来的,而是花了接近100个人年以上开发的产品,从系统架构设计,到 ORM 的选择,到安装包的准备都是无数人心血的大集成,所以要把一个成熟的产品做底层架构的基础件移植,在心理上是有些负担的。

我们的数据库移植,和网络上可以搜索到的资料本质上有很大的差别。网络上的大部分是教我们如何把数据库的资料从 MySQL 移到 PG,而不是程式中和数据库交互的代码。

以下都是我们一点一点,一步一脚印的心得体会,我们会分几期来说明。当然 ChatGPT 也帮了我们很多忙。

image


在代码中,和数据库相关的部分有几种:


1)数据库的创建和删除

2)数据库权限的设定

3)数据库表单的创建和删除

4)SQL 的语法


虽然我们选用了 ORM,但实际上在很多情形,依然是要根据业务把 SQL 语句构建出来。而以一个 MES系统来说,不考虑行业客制化方案,就至少需要100 个左右的 SQL 语句,所以这是工作量中最大的部分。


轩田科技在开发的时候,大量使用了 Docker 的技术,这次的移植我们也同样采取了 Docker 的环境。为了方便,我们下载了 PG 的官方 Docker 镜象。也就说我们用了两个容器,一个是 MES 的容器,一个是 PG 的容器,我们把 MES  Docker 中的数据库配置指向了 PG 的容器。这种方式的好处是,可以快速的重建一个干净的环境,特别是在头脑不清醒,或是疲劳开发(公司不罚钱,不警告)的情况之下,很容易做错事,污染了开发环境,这时候就可以快速的把环境清空,重新回到一个可控的情形,而不是越改越乱。这样的环境,也可以快速的交给下一个人进行开发。


而 DB 管理工具,用的则是 PG4Admin (轩田的规则是尽量开源),虽然没有商业版的强大,但也够用了。


image


以下是我们在整个移植过程的一些心得


MySQL 和 PG 在基本管控上就有了最大的差别

PG 在数据库表单和字段是有区分大小写的。MySQL不在乎 Material.Name还是 material. name ,但 PG 这两者是有很大的区别的。在数据库创建的语句如果使用大小写,那么在 SQL 语句中,也必须使用大小写。在 PG 中,如果创建的表单和字段是大小写,那在 SQL 语句中,就一定要加上 “”,例如 “Material”.“Name”,不可以是 “Material.Name”,Material.Name,而是一定要 “Material”.“Name”。


Driver 的不同差异

我们 ORM 用的是 Python 的 SQLAlchemy针对 PG 是有两个 Driver 的:psycopg2 和 pg8000,而我们选择的是 psycopg2,而不是完全不依靠原生 PG 客户端的 pg8000  (主要还是担心重新实现功能的 pg8000 效率不好)。


数据库的创建/删除虽然差别不大,但依然有微小的差别

MySQL 在 Create 时要有 Charset (我们用的是 UTF-8),但 PG 的内定就是 UTF-8 了,在 Create 时加入 Charset 反而失败。


image


IsolationLevel 的不同

PG 在整体上比 MySQL 的实现是严格一些的,这里有篇较清楚的文章说明了两者的差别:https://www.modb.pro/db/58331。在实现时,需要按不同需求做修改。


日期字段的定义

MySQL 用的是 DATETIME ,而 PG 用的是 TIMESTAMP。凡是有用到日期做为字段的表单都要修改。


转换格式

PG  需要单独定义不同类型的转换方式。例如CREATE CAST (CHARACTER VARYING AS BIGINT) WITH INOUT AS IMPLICIT;

这个定义把 Char 和 BigInt 的转换绑定了。

我对这个不太擅长,只能 Trial and Error,我其实一开始认为要双向绑定,定义了两个

  CREATE CAST (CHARACTER VARYING AS BIGINT) WITH INOUT AS IMPLICIT;

  CREATE CAST (BIGINT AS CHARACTER VARYING) WITH INOUT AS IMPLICIT;

结果居然出错了。最后发现到只需要绑定我需要的 CHARACTER VARYING -->] BIGINT

image


NULL

MySQL 和 PG 的认知是有很大差别的,特别在 String 中。MySQL 对于设定可以是 NULL 的 String 是真正意义上的 NULL,而 PG 中 NULL 的 String 是 ‘’(空字串) 。这也是代码中,MySQL 可以不插入值,而 PG 一定要插入 ‘’。


当然还有很多小小的细节,整理中,后续会慢慢分享。


有想和作者有进一步交流的人可以直接公众号留言或发邮件至:sharetek@sharetek.com.cn

image