第三周:信创!数据库迁移准备(过年好!)
当前信创工作的开展,对数据库国产化提出了要求。
数据库列表
数据库 | 类型 | 兼容性 | 是否国产 | 备注 |
---|---|---|---|---|
MySQL | 开源版、收费版 | 否 | ||
PostgreSQL | 开源 | 类似MySQL | 否 | |
mariaDB | 开源 | 完全兼容MySQL | 否 | MariaDB 是 MySQL 的一个分支,也是目前最受关注的 MySQL 数据库衍生版,被视为开源数据库 MySQL 的替代品 |
OceanBase | 收费 | Oracle 租户模式 MySQL 租户模式 | 是 | 阿里研发的原生分布式关系数据库 |
PolarDB | 收费 | 完全兼容 MySQL 高度兼容 Oracle | 是 | 阿里云新一代关系型云原生数据库,基于 MySQL 进行开发 |
DM | 收费 | 兼容 MySQL 兼容 Oracle | 是 | 达梦数据库,可通过配置更改兼容模式 |
TDSQL | 收费 | 完全兼容 MySQL 高度兼容 Oracle | 是 | 腾讯打造的一款分布式数据库产品 |
TiDB | 社区版、收费版 | 支持 MySQL 传输协议及其绝大多数语法 | 是 | TiDB 是国产开源分布式关系型数据库 |
openGauss | 开源 | 兼容 PostgreSQL | 是 | 华为推出的一款开源关系型数据库 |
GBase | 收费 | 完全兼容 MySQL | 是 | 南大通用推出的数据库 |
KingBase | 收费 | 兼容 PostgreSQL | 是 | KingBase 是基于 PostgreSQL 开发的数据库 |
ORM 工具
ORM 是对象关系映射,用于实现面向对象编程语言里不同类型系统的数据之间的转换。对于数据的操作,我们无需再去编写原生 SQL,取而代之的是基于面向对象的思想去编写类、对象、调用相应的方法等,ORM 会将其转换/映射成原生 SQL 然后执行。开发人员既不用再去考虑原生 SQL 的优化问题,也不用考虑数据库迁移的问题,ORM 都帮我们做了优化且支持多种数据库。
常见的 ORM 工具有 JPA、Hibernate 和 MyBatis 等。
兼容性写法
一、对于不同数据库平台都兼容的语句,写在 MyBatis 根目录下,差异化的语句通过 include 进行引入。
二、对于 Oracle 和 MySQL 两种类型数据库的语法兼容问题,通过数据源配置的 type 字段判断加载哪一类数据库的个性化语法 xml 文件。
二、对于信创数据库的特有语法,通过 databaseid 进行判断(MyBatis 配置类需加上数据平台 ID)。
decode 函数
改为 Oracle 和 MySQL 都适用的 case when。
rownum
由于 MySQL 中没有 rownum,所以 rownum 不再作为返回值进行返回。
startwith
改为用 Java 方法解析。
substring
文本截取统一使用 Oracle 和 MySQL 都支持的 substr,并且由于 MySQL 的 substr 不能从0开始,所以统一规定从1开始。
instr
instr 解析多值对象统一用 like 代替,推荐使用 MyBatis 中的 bind 标签。
自增
推荐使用雪花算法由 Java 生成 ID,本地生成效率更高。另外在语句中不推荐使用 ID 作为业务逻辑开发,比如排序和比较。
数据库自带的自增,Oracle 需先创建自增序列,MySQL 需将表指定字段设置为主键自增。
insert
批量插入时,要考虑兼容性,由于 Oracle 不像 MySQL 那样支持多行插入,所以统一使用 select union all 的方式。考虑可读性,单条插入不推荐使用 select 方式。
判空
Oracle 使用 nvl,MySQL 使用 if null。
转成字符型
Oracle 使用 to_char( ),MySQL 使用 cast( as character)。
转成数值型
Oracle 使用 to_number(),MySQL 为使用 cast( as unsigned int)。
查询前 n 条
Oracle 使用 where rownum <= n,MySQL 使用 limit n。
列转行
Oracle 使用 listagg(Oracle 19c 不支持 wm_concat),MySQL 使用 group_concat。
把一列的值合并为一个值,再用指定的分隔符隔开。
时间格式转换
Oracle 使用 to_char(${toCharTime},'yyyymmdd'),MySQL 使用 date_format(${toCharTime},'%Y%m%d')。
小数点保留
Oracle 使用 to_char(${toCharNumber},'FM999.099'),MySQL 使用 format(${toCharNumber},2)。
JSON 解析
改成在 Java 中进行解析。
筛选操作
对于有勾选列表后续操作的场景,筛选条件改成在 redis 中缓存。
有两种实现方法:
一、前端获取选中 ID 传入操作接口,后端根据 ID 进行逻辑处理;
二、前端将筛选条件传入操作接口,一般做法是将筛选条件存入 redis 并返回 key,后续操作时将 uuid 传入操作接口,后端获取筛选条件进行拼接。
分页
统一使用 pageHelper 插件完成。
不建议写法
分布式事务
事务的使用,尽量避免分布式事务,事务必须保证同一个数据源。
字符串拼接
在项目中拒绝使用字符串拼接,输出结果集可让前端自行拼接或使用 Java 进行拼接。
对于不得已必须使用的拼接采用通用的 concat,由于 Oracle 的 concat 函数只能连接两个字符串,所以该函数统一只传两个参数。
建议写法
判断不同条件不同查询,前面跟着 <where> 防止出现语句异常。
查询单个数据,使用 resultType 作为返回的数据类型。
对于单条数据,如果返回参数为 Map,要保证查询语句只返回一条,否则要使用 List。
下载并使用阿里巴巴代码规范插件。
接口以及接口入参定义好 swagger 文档说明以及日志。
对接口传参的判断尽量使用注解完成,减少接口中判断参数的 if 语句。
grpc 调用中协议字段必须加上注释。
日志打印必须将捕获的异常变量 e 传到日志打印的方法中,打印的文字不要使用 + 进行字符串拼接,会影响执行效率,需要使用 {} 做占位符,然后在方法后面的参数中传入对应变量,最后多传一个异常变量 e。
事务处理需要在 server 端的 service 层加上 @Transactional 注解,必须指明事务管理器,否则和其他模块打包在一起的时候会报找不到事务管理器。
每次写完需要注意事务是否生效,可以在两个数据库操作中增加手动抛异常的操作来测试是否可以回滚。
使用事务的时候需要注意事务失效的情况:数据库引擎不支持事务、没有被 Spring 管理、方法不是 public、自身调用、数据源没有配置事务管理器、异常的类型不对或者异常被捕获。
遇到网关需要调用多个 server 来完成一个接口调用,且两个调用之间需要保持事务关系时,将多个 server 的接口代码迁移到一个 server 中,然后按正常的事务写法写(这一种情况可忽略微服务职责划分的规范,不推荐使用分布式事务)。
编写单元测试,对于数据库操作直接编写 mapperTest 去做测试,不用每次都用 swagger 去做测试。
信创迁移
安装目标迁移数据库,查阅文档进行数据迁移,完成后验证数据的完整性和正确性。