多个项目平替升级表结构不统一咋办?数据库mysql幂等性终结
本本分分做人,踏踏实实做事!!!
前言
- 随着项目分支越来越多,对于年久失修的项目每一次的升级都是伤筋动骨的。因为年久失修的项目是很难准确描述出缺少的必要条件。比如说距离上次发布至今我们数据库发生的变动。我们在发布期间需要将这些变动的数据库更新上来才能保证新版本正常的运行。
- 针对上面的数据库版本太老的原因,我们可以通过对比工具和新数据库进行对比生成差集
sql
。然后我们将这个 sql 到就数据库上执行一遍就行了。但是这个过程还是有缺陷的,比对的过程需要我们认为参与,且针对非必填字段改为必填字段就很难解决。 liqui-base
是一个对数据库进行版本管理的一个框架。我们通过liqui-base
能够将我们数据库的变更进行记录下来。你可以简单理解我们准备了一份基础数据。随着项目不断的迭代,我们将每次迭代的 sql 文件本地化存储下来。然后liqui-base
将每个本地化文件进行 MD5 加密。每次通过 MD5 进行确认是否执行过该迭代版本。这样就能够保证数据库的最新。该功能我们只需要保证我们每次提供的 sql 的正确性。- 今天我们针对 sql 来展开谈谈如何保证 sql 的正确性。
场景
liqui-base
技术已经很成熟了,理论上我们只需要提供正确的 sql 即可。但是因为我们公司的独特性,导致liqui-base
无法正确的执行,某种场景下会发生 1 个 sql 重复执行。虽然重复执行问题不大,但是部分 sql 是无法忍受的。- sql 文件中存在
insert
,重复执行就会导致数据 Double (假设没有触发唯一建约束!)。 - 这个肯定是我们改造
liqui-base
导致的,我们后续也修复了。但是今天我想讲的不是修复的问题,而是如何保证我们提供的 sql 的幂等性!!!
具体案例
data 幂等
- 现在我们有一张
business
表。迭代的 sql 中需要向这张表中添加一份数据。
CREATE TABLE nanshan.business (
id INT auto_increment NOT NULL COMMENT '主键',
name varchar(100) NULL COMMENT '名称',
CONSTRAINT main_pk PRIMARY KEY (id)
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_0900_ai_ci
COMMENT='业务名称';
insert business(name) values('zxhtom');
- 这种情况我每执行一次就会生成一个 name=zxhtom 的数据。虽说 name 字段设计的本身可以重复,但是 insert 作为基础数据因为重复执行导致数据重复了,总感觉是乖乖的。
- 经过一番摸索,我发现可以借助
existsl
关键字来实现判断是否INSERT
。
insert business(name) select 'zxhtom' from dual where not exists (select 1 from business where name='zxhtom');
- 通过上面截图我们也能够发现第一次插入 zxhtom 数据后,第二次插入也成功了但是影响的是 0rows . 说明 mysql 已经成功执行了这条 sql。但是这条 sql 并没有产生任何数据。
- 这样就保证了该 sql 的幂等性。
DDL 幂等
- 迭代过程提供的 sql 很大可能都是 DDL 的修改。INSERT 反而是很少的情况。那么关于 DDL 我们如何实现幂等呢?
- 首先就是我们建表语句。
create table test01(id int , name varchar(255))
- 建表是我们通过
NOT EXISTS
关键字判断。但是在新增或者修改字段是好想无法使用这个关键字。
- 为了能够实现和建表相同的逻辑。我们这里接住存储过程来解决这个问题。
DROP PROCEDURE IF EXISTS proc_tempPro;
delimiter ;;
CREATE PROCEDURE proc_tempPro()
BEGIN
SELECT count(*) into @count FROM INFORMATION_SCHEMA.Columns
WHERE table_schema= DATABASE() AND table_name="t_assets" AND column_name="repository_id4";
if(@count=0) THEN
ALTER TABLE t_assets add repository_id4 VARCHAR(255) NULL COMMENT '所属仓库';
end if;
end;;
delimiter ;
call proc_tempPro;
DROP PROCEDURE IF EXISTS proc_tempPro;
- 这样编写我们的 sql 就能保证幂等性了。再也不怕重复执行了。
总结
- 幂等性对于开发程序来说还是很重要的。因为客户很有可能因为客户端卡顿不停的点击。或者因为客户端的 BUG 导致不停的重复调用接口。再或者别人恶意攻击我们。这个时候幂等性就尤其重要。本文主要介绍了 sql 的幂等性。后面我们在了解下接口如何实现幂等性。
放松一刻
It is not fair to ask of others what you are unwilling to do yourself. — Eleanor Roosevelt