1. 程式人生 > 程式設計 >使用指令碼對資料庫進行遷移

使用指令碼對資料庫進行遷移

為什麼要進行資料遷移與修復

在日常工作開發中,隨著我們產品不斷迭代發展,我們希望在重構功能的同時,還需要保證在版本迭代之前操作資料保留並且變更得能夠適應新的功能結構,這個時候往往會存在資料表的大量修改與變動,就是我們通常所說的 平滑升級

程式碼中使用定時任務

  1. 在程式碼中使用定時任務來對資料庫進行資料遷移與修復時,一般都會存在讀取、更改、插入等操作,如果資料量很大,那麼修復時耗會使得我們難以接受。
  2. 更糟糕的是如果我們系統使用到的是微服務架構,微服務之間的通訊呼叫也存在著時間損耗,這裡進一步使得時耗盡延長。
  3. 但如果使用的是shell指令碼,速度將會大大提升,比如我們在程式碼中進行資料修復要花掉5分鐘時間,使用指令碼修復可以只需要2秒。

Mysql - 這裡舉例三個微服務:

需要被同步的微服務資料庫 - 新表存在的服務:base_service 需要同步資料的 - 舊錶存在的服務:devops_service,agile_service

如果要修復的資料在同一臺伺服器上,而且你只想匯出部分欄位到所需的表中,那麼:

只需要連線上資料庫,使用sql將資料查詢出來再插入就可以了(這裡,sql靈活多變,你可以根據自己的同步資料策略進行修改)

mysql -u$BaseDBUSER -p$BaseDBPASS -h $BaseDBHOST << EOF
use ${base_service};
insert into ${base_service}.${base_service_table_app}(id,name,code,organization_id,image_url,type) 
select id,'custom'
from ${base_service_table_project}; insert into ${base_service}.${base_service_table_app_service}(id,is_active,app_id,type,img_url) select id,img_url from ${devops_service}.${devops_service_table_das}; insert into ${base_service}.${base_service_table_app_version}(name,status,start_date,release_date,application_id,description) select name,status_code,project_id as application_id,description from ${agile_service}.${agile_service_table_apv}; EOF 複製程式碼

這裡再思考一個問題,修復資料是在什麼時候

一般來說是使用者部署我們的服務的時候,就需要對資料庫進行遷移修復,那如果使用者進行多次部署呢?這裡mysql的話使用儲存過程實現校驗資料是否已經遷移修復了,如果已經遷移過就不需要再進行修復了。

如果要修復的資料在不同伺服器上,那麼:

我們需要將agile_service,devops_service的資料先匯出,插入表與資料到base_service,然後使用sql對資料進行修復,再刪除掉匯入進來的舊錶就好了。

# 第二種方案 - 各個微服務的資料在不同伺服器上

# 同步devops_app_service資料到base_service
# 匯出舊錶資料及結構到需要被遷移的資料庫表中
mysqldump -u$DevopsDBUSER -p$DevopsDBPASS -h $DevopsDBHOST -P$DevopsDBPORT \
${devops_service} ${devops_service_table_das} \
| mysql -u$BaseDBUSER -p$BaseDBPASS -h $BaseDBHOST -P$BaseDBPORT ${base_service}

# 同步agile_app_service資料到base_service
# 匯出舊錶資料及結構到需要被遷移的資料庫表中
mysqldump -u$AgileDBUSER -p$AgileDBPASS -h $AgileDBHOST -P$AgileDBPORT \
${agile_service} ${agile_service_table_apv} \
| mysql -u$BaseDBUSER -p$BaseDBPASS -h $BaseDBHOST -P$BaseDBPORT ${base_service}

# 遷移資料到新表並刪除舊錶
mysql -u$BaseDBUSER -p$BaseDBPASS -h $BaseDBHOST -P$BaseDBPORT << EOF
use ${base_service};
drop procedure if exists sync_data;
delimiter //
create procedure sync_data()
begin
declare syncProNum int;
declare syncAppServiceNum int;
declare syncAppVersionNum int;

select count(id) into syncProNum from ${base_service_table_project} where APPLICATION_ID is NULL;
if (syncProNum != 0) then
update ${base_service_table_project} set application_id = id;
insert into ${base_service_table_app}(id,type) select id,'custom' from ${base_service_table_project};
end if;

select count(id) into syncAppServiceNum from ${base_service_table_app_service};
if (syncAppServiceNum = 0) then
insert into ${base_service_table_app_service}(id,img_url) select id,img_url from ${devops_service_table_das};
end if;

select count(id) into syncAppVersionNum from ${base_service_table_app_version};
if (syncAppVersionNum = 0) then
insert into ${base_service_table_app_version}(id,description)  select version_id as id,description from ${agile_service_table_apv};
end if;

end//
delimiter ;

SET @@autocommit=0;
call sync_data;
SET @@autocommit=1;
drop table ${devops_service_table_das};
drop table ${agile_service_table_apv};
drop procedure if exists sync_data;
EOF
複製程式碼
  • 這裡需要特別注意一個問題:mysql的預設結束符是;,但使用儲存過程的時候是不允許使用;的,所以這裡需要使用delimiter去修改一下結束符號的標誌。即程式碼中的:delimiter //修改結束符號為//

Oracle - 使用agile與base兩個微服務:

需要被同步的微服務資料庫 - 新表存在的服務:base_service 需要同步資料的 - 舊錶存在的服務:agile_service

同一臺伺服器資料遷移修復和mysql相同,使用Oracle命令連線上伺服器資料庫就行了
多臺伺服器資料遷移修 - 使用dblink
sqlplus $BaseDBUSER/$BaseDBPASS@//$BaseDBHOST:$BaseDBPORT/sid << EOF
create public database link agile_service_link
connect to system identified by password
using 'agile_service';
begin
insert into ${base_service_table_app_version}(id,type)  
select id,'custom' from ${agile_service_table_apv}@agile_service_link;
commit;
exception
when others
then
dbms_output.put_line('Exception happened,data was rollback');
rollback;
end;
EOF
複製程式碼