詳解如何在數倉中搭建細粒度容災應用

来源:https://www.cnblogs.com/huaweiyun/p/18000551
-Advertisement-
Play Games

本文介紹了在雲上環境的雙集群(不跨Region不跨VPC)後臺手動部署並使用細粒度容災的主要步驟,使得用戶能快速方便得搭建起細粒度容災。 ...


本文分享自華為雲社區《GaussDB(DWS)細粒度容災使用介紹》,作者: 天藍藍。

1. 前言

適用版本:【8.2.1.210及以上】

當前數倉承載的客戶業務越來越多,從而導致客戶對於數倉的可靠性要求不斷增加。尤其在金融領域,容災備份機制是信息系統必須提供的能力之一。本文介紹了在雲上環境的雙集群(不跨Region不跨VPC)後臺手動部署並使用細粒度容災的主要步驟,使得用戶能快速方便得搭建起細粒度容災。

2. 細粒度容災簡介

對於MPPDB集群的容災而言,目前業界的常見方案要麼是部署兩套規格配置同等的集群,要麼通過邏輯雙載入方式去實現,這兩個方案缺點比較明顯,存在架構複雜、建設成本高等問題,不僅使得災備部署難度增大,還導致資源浪費。在此背景下,GaussDB(DWS)基於列存表實現細粒度容災能力,既滿足核心分析型業務在極端場景的業務連續性要求,同時也能大幅降低容災方案的建設成本,而且容災架構輕量化,容災系統易運維、易操作、易演練,從而幫助用戶迅捷、經濟、按需構建核心業務的容災系統。

相比於傳統的容災方案,細粒度容災有以下優勢:

  • 主集群和備集群雙活(Active-Active)(備集群除災備表只讀外,其餘表可讀寫)
  • 主備集群只需滿足DN整數倍關係,降低備集群建設資源,方便靈活部署
  • 利用列存表的數據和元數據分離的特點,通過元數據邏輯同步 + 數據物理同步的方式,同步增量,結合UDF的增量抽取/回放介面,保障表級數據一致性
  • 粒度可控,支持表級、schema級、庫級容災
  • 支持表DDL,部分DCL元數據同步,達到切換可用

細粒度容災示意圖

3. 容災前準備

3.1 配置互信

前提條件

  • 確保ssh服務打開。
  • 確保ssh埠不會被防火牆關閉。
  • 確保所有機器節點間網路暢通。

配置互信

依次登錄主備集群各節點沙箱外,執行步驟2-4。

將主集群和備集群所有節點ip和hostname添加到/home/Ruby/.ssh/authorized_keys和/var/chroot/home/Ruby/.ssh/authorized_keys的from列表中。

將主集群和備集群所有節點ip和hostname的映射添加到/etc/hosts和/var/chroot/etc/hosts文件中。

遍歷主集群和備集群所有節點ip和hostname,執行以下命令。

ssh-keyscan -t rsa -T 120 ${ip/hostname} >> /home/Ruby/.ssh/known_hosts
ssh-keyscan -t rsa -T 120 ${ip/hostname} >> /var/chroot/home/Ruby/.ssh/known_hosts

校驗互信

從主集群任一節點能免密ssh到備集群任一節點且從備集群任一節點能免密ssh到主集群任一節點,即代表互信已配置成功。

3.2 配置容災配置文件

  1. Ruby用戶分別登錄主備集群主節點沙箱內。
  2. 創建容災目錄,假設目錄為/DWS/data2/finedisaster。mkdir -p /DWS/data2/finedisaster
  3. 在/DWS/data2/finedisaster目錄下,創建容災配置文件backupRestore.ini和主備集群倒換配置文件sw_backupRestore.ini。

註意:

細粒度容災的容災備份過程支持與物理細粒度備份業務並行執行。可通過以下措施隔離:

兩個備份任務指定不同的metadata目錄和media目錄,實現備份數據隔離。容災備份目錄通過容災配置文件(backupRestore.ini和sw_backupRestore.ini)中的參數primary-media-destination和primary-metadata-destination指定。

細粒度容災的容災備份埠與物理細粒度備份的master-port指定為不同的值,實現備份進程埠的隔離。容災的備份埠通過容災配置文件(backupRestore.ini和sw_backupRestore.ini)中的參數backup-port指定。

容災配置文件backupRestore.ini

以下是backupRestore.ini文件示例,可根據具體業務場景修改配置參數值。

# Configuration file for SyncDataToStby tool
# The backup life cycle
life-cycle=10m
# The table that records backups info
backuprestoreinfo-file=backuprestoreinfo.csv
# The cluster user name for cluster
username=Ruby
# The primary cluster env set
primary-env=
# The standby cluster env set
standby-env=
# Time interval between each full backup, uint: min
full-backup-exec-time-interval=N/A
# Time interval between each backup
backup-exec-time-interval=2
# One of the backup hosts
primary-host-ip=XXX.XXX.XXX.XX
# The media type that restore backup files, DISK
media-type=disk
# The number of process that should be used. Range is (1~32)
parrallel-process=4
# The compression level that should be used for backup. Range(0~9)
compression-level=1
compression-type=2
# Media destination where the backup must be stored
primary-media-destination=/DWS/data2/finedisaster/mediadata
# Metadata destination where the metadata must be stored
primary-metadata-destination=/DWS/data2/finedisaster/metadata
# The master-port in which the backup must be executed
backup-port=XXXX
# Logging level for the log contents of backup:FATAL,ERROR,INFO,DEBUG
primary-cluster-logging-level=INFO
# Time interval between each restore, uint: min
restore-interval=2
# One of the restore hosts
restore-host-ip=XXX.XXX.XXX.XX
# Media destination where the backup contents must be stored in the standby cluster
restore-media-destination=/DWS/data2/finedisaster/mediadata
# Metadata destination where the backup contents must be stored in the standby cluster
restore-metadata-destination=/DWS/data2/finedisaster/metadata
# The master-port in which the restore must be executed
restore-port=XXXX
# Logging level for the log contents of restore
standby-cluster-logging-level=INFO
# The maximum number of log files that should be created. Range is (5~1024).
log-file-count=50
# The retry times of checking cluster balance for resuem backup or double clusters
check-balance-retry-times=0
# cluster id
primary-cluster-id=11111111-1111-1111-1111-111111111111
standby-cluster-id=22222222-2222-2222-2222-222222222222
# Processes tables for which fine-grained disaster recovery is no longer performed
# Value should be 'none', 'log-desync-table', 'drop-desync-table'
desync-table-operation=drop-desync-table
# Number of CPU cores that can be used by each DR process. Range is (1~1024).
cpu-cores=8
# The max number of rch files that can be reserved on master cluster before sent to standby cluster. 0 means no limit.
local-reserve-file-count=160

主備集群倒換配置文件sw_backupRestore.ini相比於backupRestore.ini只需顛倒下列參數

  • primary-host-ip / restore-host-ip
  • backup-port / restore-port
  • primary-media-destination / restore-media-destination
  • primary-metadata-destination / restore-metadata-destination
  • primary-cluster-id / standby-cluster-id

配置文件主要參數說明

參數名參數含義
username 執行雙集群腳本的OS用戶,設置成GaussDB(DWS)集群相同的OS用戶
primary-env 主集群的環境變數存儲文件的絕對路徑
standby-env 備集群的環境變數存儲文件的絕對路徑
backup-exec-time-interval 增量備份周期
primary-host-ip 主集群執行備份的節點ip
compression-type 備份文件的壓縮演算法類型
compression-level 備份文件的壓縮級別
primary-media-destination 主集群上存放備份文件的絕對路徑
primary-metadata-destination 主集群上備份元數據的絕對路徑
backup-port Roach主代理備份進程的執行埠
restore-interval 恢復周期
restore-host-ip 備集群執行恢復的節點ip
restore-media-destination 備集群存放主集群同步的備份文件的路徑
restore-metadata-destination 備集群存放主集群同步的元數據信息的路徑
restore-port 恢復進程執行埠
primary-cluster-id 指定主集群的UUID
standby-cluster-id 指定備集群的UUID
new-disaster-recovery-suppressed-time-windows 指定主集群不發起新一輪備份的時間視窗
desync-table-operation 指定不再進行細粒度容災的表,在備集群上的處理方式
cpu-cores 指定容災每個進程能使用的cpu核數
local-reserve-file-count 在發送到備用群集之前,可以在主群集上保留的最大rch文件數。0表示無限制。

3.3 主備集群準備

Ruby用戶登錄主集群主節點沙箱內。

設置集群GUC參數。

local-dn-num為本集群DN數,remote-dn-num為對方集群DN數,可替換為實際值。

python3 $GPHOME/script/DisasterFineGrained.py -t prepare --local-dn-num 6 --remote-dn-num 3 --config-file /DWS/data2/finedisaster/backupRestore.ini

3.4 容災表數據準備

主集群連接資料庫,準備容災表數據。

新建容災表
create table schema1.table_1(id int, name text) with (orientation = column, colversion="2.0", enable_disaster_cstore="on", enable_delta=false) DISTRIBUTE BY hash(id);
存量表(非容災表)轉為容災表
alter table schema1.table_1 set (enable_disaster_cstore='on');
--查詢表的分佈方式
select pclocatortype from pg_catalog.pgxc_class where pcrelid = 'schema1.table_1'::regclass::oid limit 1;
--若表的分佈方式為H(HASH分佈),獲取一個hash表的分佈列,後續以'id'列分佈為例
select pg_catalog.getdistributekey('schema1.table_1');
--對錶做重分佈
alter table schema1.table_1 DISTRIBUTE BY HASH(id);
--若表的分佈方式為N(ROUNDROBIN分佈),對錶做重分佈
alter table schema1.table_1 DISTRIBUTE BY ROUNDROBIN;
--若表的分佈方式為R(REPLICATION分佈),對錶做重分佈
alter table schema1.table_1 DISTRIBUTE BY REPLICATION;

4. 細粒度容災操作

4.1 定義發佈

Ruby用戶登錄主集群主節點沙箱,以下操作均在沙箱內進行。

連接資料庫,通過發佈語法指定需要容災的主表,語法如下:
--發佈所有表
CREATE PUBLICATION _pub_for_fine_dr FOR ALL TABLES;
--發佈schema
CREATE PUBLICATION _pub_for_fine_dr FOR ALL TABLES IN SCHEMA schema1, schema2;
--發佈表和schema
CREATE PUBLICATION _pub_for_fine_dr FOR ALL TABLES IN SCHEMA schema1, TABLE schema2.table_1;
--增加一個發佈表
ALTER PUBLICATION _pub_for_fine_dr ADD TABLE schema1.table_1;
--增加發佈SCHEMA
ALTER PUBLICATION _pub_for_fine_dr ADD ALL TABLES IN SCHEMA schema2;
定義發佈後,將容災publication放到參數文件中,以dbname.pubname形式,例如:
echo 'dbname._pub_for_fine_dr' > /DWS/data2/finedisaster/pub.list

若需要解除發佈,通過DisasterFineGrained.py腳本下發cancel-publication命令

# 1、創建需要取消的容災對象列表文件
# 解除發佈表
echo 'db_name.schema_name.table_name' > /DWS/data2/finedisaster/config/disaster_object_list.txt
# 解除發佈SCHEMA
echo 'db_name.schema_name' > /DWS/data2/finedisaster/config/disaster_object_list.txt

# 2、下發cancel-publication命令
python3 $GPHOME/script/DisasterFineGrained.py -t cancel-publication --disaster-object-list-file /DWS/data2/finedisaster/config/disaster_object_list.txt --config-file /DWS/data2/finedisaster/backupRestore.ini

# 3、取消全部發佈
python3 $GPHOME/script/DisasterFineGrained.py -t cancel-publication --config-file /DWS/data2/finedisaster/backupRestore.ini --all-cancel

4.2 啟動容災

註意:

雲上集群沙箱內無法啟動crontab任務,需要在主備集群沙箱外手動添加定時備份恢復任務

HCS 8.3.0及以上環境,沙箱外crontab設置ssh到沙箱內的定時任務,為了防止沙箱逃逸,ssh前需要加上"sudo python3 /rds/datastore/dws/​​​XXXXXX/sudo_lib/checkBashrcFile.py && source /etc/profile && source ~/.bashrc && ",否則定時任務不生效。checkBashrcFile.py文件路徑與版本號有關。

主集群主節點沙箱外設置定時任務,crontab -e。註意替換主節點IP。
*/1 * * * * nohup ssh XXX.XXX.XXX.XXX "source /etc/profile;if [ -f ~/.profile ];then source ~/.profile;fi;source ~/.bashrc;nohup python3 /opt/dws/tools/script/SyncDataToStby.py -t backup  --config-file /DWS/data2/finedisaster/backupRestore.ini --disaster-fine-grained --publication-list /DWS/data2/finedisaster/pub.list  >>/dev/null 2>&1 &"  >>/dev/null 2>&1 &
備集群主節點沙箱外設置定時任務,crontab -e。註意替換主節點IP。
*/1 * * * * nohup ssh XXX.XXX.XXX.XXX "source /etc/profile;if [ -f ~/.profile ];then source ~/.profile;fi;source ~/.bashrc;nohup python3 /opt/dws/tools/script/SyncDataToStby.py -t restore  --config-file /DWS/data2/finedisaster/backupRestore.ini  --disaster-fine-grained  >>/dev/null 2>&1 &" >>/dev/null 2>&1 &

成功啟動備份確認。

Ruby用戶分別登錄主備集群主節點沙箱,查詢SyncDataToStby.py進程是否存在。
ps ux | grep SyncDataToStby | grep -v grep
Ruby用戶登錄主/備集群主節點沙箱,使用roach的show-progress監控工具,查看備份/恢復進度。show-progress命令提供主備集群備份恢復進度等信息, 顯示結果為json格式,各欄位含義請參考產品文檔。
python3 $GPHOME/script/SyncDataToStby.py -t show-progress --config-file /DWS/data2/finedisaster/backupRestore.ini

系統回顯:

{
  "primary cluster": {
    "key": "20231109_212030",
    "priorKey": "20231109_211754",
    "actionType": "Backup",
    "progress": "100.00%",
    "backupRate": {
      "producerRate": "0MB/s",
      "compressRate": "0MB/s",
      "consumerRate": "0MB/s"
    },
    "currentStep": "FINISH",
    "unrestoreKeys": "N/A",
    "failedStep": "INIT",
    "errorMsg": "",
    "errorCode": "",
    "actionStartTime": "2023-11-09 21:20:28",
    "actionEndTime": "2023-11-09 21:20:49",
    "updateTime": "2023-11-09 21:20:50"
  },
  "standby cluster": {
    "key": "20231109_175002",
    "priorKey": "N/A",
    "actionType": "Restore",
    "progress": "100.00%",
    "backupRate": {
      "producerRate": "0MB/s",
      "compressRate": "0MB/s",
      "consumerRate": "0MB/s"
    },
    "currentStep": "FINISH",
    "unrestoreKeys": "20231109_211754,20231109_212030",
    "failedStep": "INIT",
    "errorMsg": "",
    "errorCode": "",
    "actionStartTime": "2023-11-09 17:53:07",
    "actionEndTime": "2023-11-09 17:53:15",
    "updateTime": "2023-11-09 17:53:15"
  },
  "apply": {
    "backupState": "waiting",
    "restoreState": "waiting",
    "backupSuccessTime": "2023-11-09 21:21:24",
    "restoreSuccessTime": "2023-11-09 17:53:55"
  },
  "latestBarrierTime": "",
  "recovery point objective": "3:32:17",
  "failover recovery point time": ""
}

show-progress命令顯示的主要欄位釋義如下

  • priorKey:該備份集是基於這個backup key生成的。
  • actionType:備份集當前的操作類型。
    取值包括如下:
    • Backup,表示備份階段。
    • Restore,表示恢復階段。
  • progress:備份或恢復操作的進度。
  • currentStep:備份或恢復正在執行的步驟。
  • unrestoreKeys:待恢復的key列表。
  • failedStep:備份或恢復失敗的步驟,初始值預設為INIT。
  • errorMsg:備份或恢復失敗的錯誤信息,如果成功,該欄位則顯示成功的信息。
  • errorCode:備份或恢復的錯誤碼,該欄位為預留欄位,暫未使用。
  • actionStartTime:當前操作的開始時間。
  • actionEndTime:當前操作的結束時間。
  • updateTime:當前操作進度的刷新時間。
  • backupState:當前備份狀態(backuping/stopped/waiting/abnormal)。
  • restoreState: 當前恢復狀態(restoring/stopped/waiting/abnormal)。
  • backupSuccessTime:上次成功備份結束的時間。
  • restoreSuccessTime:上次成功恢復結束的時間。
  • latestBarrierTime:上次主備集群一致點時間。
  • recovery point objective:rpo時間(當前主集群時間到最後一個恢覆成功的備份集備份開始時間)。
  • failover recovery point time:failover未同步時間點。

4.3 結果驗證

4.3.1 功能驗證

同步前後進行數據一致性校驗,主表、備表數據進行checksum校驗,檢查是否同步正確(需排除由於接入業務導致的差異)。

4.3.2 性能驗證

通過show-progress監控工具可以看到最近一次備份、恢復耗時。

5. 解除容災

5.1 停止容災

# 主備集群取消沙箱外的定時容災任務,在備份/恢復任務前添加註釋符“#”,取消定時任務
crontab -e
# 主集群Ruby用戶登錄主節點沙箱,停止備份
python3 $GPHOME/script/SyncDataToStby.py -t stop-backup --config-file /DWS/data2/finedisaster/backupRestore.ini --disaster-fine-grained
# 備集群Ruby用戶登錄主節點沙箱,停止恢復
python3 $GPHOME/script/SyncDataToStby.py -t stop-restore --config-file /DWS/data2/finedisaster/backupRestore.ini --disaster-fine-grained

5.2 刪除容災

警告

當不再需要容災任務的時候,可以解除主備關係,恢復備集群的讀寫能力。刪除容災前需要先停止容災。

Ruby用戶登錄主集群主節點的沙箱內。

python3 $GPHOME/script/SyncDataToStby.py -t set-independent --config-file /DWS/data2/finedisaster/backupRestore.ini --disaster-fine-grained

系統回顯:

Delete csv file.
Delete roachbackup file from XXX.XXX.XXX.XX
Delete roachbackup file from XXX.XXX.XXX.XX
Clear cluster disaster state.

6. 總結

本文介紹了在雲上環境的雙集群(不跨Region不跨VPC)後臺手動部署並使用細粒度容災的主要步驟,分為容災前準備、細粒度容災操作和解除容災,使得用戶能快速方便得搭建起細粒度容災。

點擊關註,第一時間瞭解華為雲新鮮技術~


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • “中國資料庫市場已進入關鍵階段,2024年或是分水嶺!” “目前,國內資料庫產品數量接近300款,我們真的需要這麼多資料庫嗎?”面對這個問題,華為雲資料庫業務CTO蘇光牛不假思索地給出了他的見解: “不僅是中國市場,全球範圍內,也不需要如此多的商業資料庫。” 他進一步預測,隨著市場的自然淘汰,未來三 ...
  • 這篇筆記咱主要記錄了Hadoop執行Job時可能出現的 /bin/java: No such file or directory 以及 java.lang.reflect.InaccessibleObjectException 問題。 ...
  • Redis的Java客戶端-Jedis 在Redis官網中提供了各種語言的客戶端,地址:https://redis.io/docs/clients/ 其中Java客戶端也包含很多: 標記為❤的就是推薦使用的java客戶端,包括: Jedis和Lettuce:這兩個主要是提供了Redis命令對應的AP ...
  • 轉載:【PostgreSQL架構】PostgreSQL的最佳群集高可用性方案-騰訊雲開發者社區-騰訊雲 (tencent.com) 如果您的系統依賴PostgreSQL資料庫並且您正在尋找HA的集群解決方案,我們希望提前告知您這是一項複雜的任務,但並非不可能實現。 我們將討論一些解決方案,您可以從中 ...
  • 1 月 31 日,InfoQ 極客傳媒合作伙伴年度盛典在北京舉辦,圍繞“有被 Q 到”主題精彩展開。GreatSQL受邀參會,與諸多IT行業伙伴相聚一堂,共築開發者生態,共話技術前沿與商業創新。 會議期間,InfoQ 為全國技術行業做出突出貢獻的企業和項目進行了頒獎。GreatSQL 開源資料庫社區 ...
  • SQL的相關語法記錄 【連接】 相關內容參考: 一張圖看懂 SQL 的各種 join 用法_51CTO博客_sql join用法 SQL FULL OUTER JOIN 關鍵字 | 菜鳥教程 (runoob.com) 一文講懂SQL外連接OUTER JOIN - 知乎 (zhihu.com) INN ...
  • 2024年1月2日,北京白鯨開源科技有限公司(以下簡稱"白鯨開源")榮幸宣佈,白鯨開源旗下產品 WhaleStudio V2.4 已成功通過與麒麟軟體有限公司旗下的銀河麒麟高級伺服器操作系統產品的相容性測試。 麒麟軟體有限公司的銀河麒麟高級伺服器操作系統(飛騰版)V10和銀河麒麟高級伺服器操作系統( ...
  • 本文介紹瞭如何通過子查詢優化深度分頁查詢,以減少回表操作帶來的性能損耗。傳統的深度分頁查詢往往會面臨嚴重的性能問題,尤其在處理大量數據時更是如此。 ...
一周排行
    -Advertisement-
    Play Games
  • 1、預覽地址:http://139.155.137.144:9012 2、qq群:801913255 一、前言 隨著網路的發展,企業對於信息系統數據的保密工作愈發重視,不同身份、角色對於數據的訪問許可權都應該大相徑庭。 列如 1、不同登錄人員對一個數據列表的可見度是不一樣的,如數據列、數據行、數據按鈕 ...
  • 前言 上一篇文章寫瞭如何使用RabbitMQ做個簡單的發送郵件項目,然後評論也是比較多,也是準備去學習一下如何確保RabbitMQ的消息可靠性,但是由於時間原因,先來說說設計模式中的簡單工廠模式吧! 在瞭解簡單工廠模式之前,我們要知道C#是一款面向對象的高級程式語言。它有3大特性,封裝、繼承、多態。 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 介紹 Nodify是一個WPF基於節點的編輯器控制項,其中包含一系列節點、連接和連接器組件,旨在簡化構建基於節點的工具的過程 ...
  • 創建一個webapi項目做測試使用。 創建新控制器,搭建一個基礎框架,包括獲取當天日期、wiki的請求地址等 創建一個Http請求幫助類以及方法,用於獲取指定URL的信息 使用http請求訪問指定url,先運行一下,看看返回的內容。內容如圖右邊所示,實際上是一個Json數據。我們主要解析 大事記 部 ...
  • 最近在不少自媒體上看到有關.NET與C#的資訊與評價,感覺大家對.NET與C#還是不太瞭解,尤其是對2016年6月發佈的跨平臺.NET Core 1.0,更是知之甚少。在考慮一番之後,還是決定寫點東西總結一下,也回顧一下.NET的發展歷史。 首先,你沒看錯,.NET是跨平臺的,可以在Windows、 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 添加節點(nodes) 通過上一篇我們已經創建好了編輯器實例現在我們為編輯器添加一個節點 添加model和viewmode ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...
  • 類型檢查和轉換:當你需要檢查對象是否為特定類型,並且希望在同一時間內將其轉換為那個類型時,模式匹配提供了一種更簡潔的方式來完成這一任務,避免了使用傳統的as和is操作符後還需要進行額外的null檢查。 複雜條件邏輯:在處理複雜的條件邏輯時,特別是涉及到多個條件和類型的情況下,使用模式匹配可以使代碼更 ...
  • 在日常開發中,我們經常需要和文件打交道,特別是桌面開發,有時候就會需要載入大批量的文件,而且可能還會存在部分文件缺失的情況,那麼如何才能快速的判斷文件是否存在呢?如果處理不當的,且文件數量比較多的時候,可能會造成卡頓等情況,進而影響程式的使用體驗。今天就以一個簡單的小例子,簡述兩種不同的判斷文件是否... ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...