国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > 綜合 > 正文

用AWK實現DB2 數據庫 Schema的同步(1)

2024-07-21 02:41:36
字體:
來源:轉載
供稿:網友
  在多個成員用一個系統進行集成測試時,每一個成員 PC 機上也要安裝一個相同的數據庫作為單元測試環境。本文介紹了保持各個數據庫一致性——我們稱這個過程為數據庫 schema 的同步——的幾種方式。  場景說明  我們在項目中經常碰到這樣一種情況:項目組所有成員共用一個系統集成測試環境(SIT)中的數據庫,每一個成員PC機上也安裝一個相同的數據庫作為單元測試環境。因為業務模型的變化,導致數據庫結構發生變化時,通常由數據庫治理員根據數據模型組的需求修改SIT的數據庫結構,并保持原有數據的延續性。此時,PC機上單元測試數據庫結構與SIT數據庫結構就可能不一致,通常有以下幾種方式來繼續保持它們的一致性(我們稱這個過程為數據庫SCHEMA的同步):  1、 由模型組或者數據庫治理員發布數據庫修改的命令清單,各成員按照清單逐步操作,實現數據庫SCHEMA的同步。這種方法要求每一次SIT數據庫SCHEMA的修改都必須被記錄在案,并通知到項目組每一個成員。假如某個成員遺漏了其中某一次修改,則他以后的修改都可能會有問題。當然,他也可以從其他成員的單元測試環境中備份、恢復最新版的數據庫。  2、 由數據庫治理員將SIT數據庫整庫備份,各成員在PC機上刪除原有數據庫,恢復該備份數據庫。這種方法看起來總能得到最新的SCHEMA和數據,但通常比較難于實施。因為SIT環境通常在UNIX環境下,而單元測試環境通常在WINDOWS環境下,二者對于磁盤設備的治理方式相差甚大,通過數據庫備份工具得到的備份文件,在不同操作系統下恢復時,對于磁盤設備不同導致的修改相當麻煩。同時,SIT環境的數據量通常比較大,有的項目甚至于會定期從生產線上獲取最新的數據,而單元測試環境通常是在PC機上,所能提供的磁盤空間相對較小,多數情況下都不足以恢復全量的SIT數據庫。 12345678910下一頁   3、 由模型組或者數據庫治理員發布數據庫修改的通知,各成員采用本文所描述的方法,根據SIT數據庫最新的SCHEMA,用PC機上的數據同步數據庫。這種方法采用本文提供的SHELL程序,可以比較快的完成,其中僅需要較小的人工干預。并且,這種方法也能保持單元測試環境中數據的延續性。  本文說明如何實現第三種方法,完成DB2數據庫的同步。  本文所使用的環境為:  SIT環境:AIX UNIX 5.1、DB2 8.1。  單元測試環境:Windows xp、DB2 8.1 for Windows、cygwin。  本文使用如下約定:  數據庫的名稱為cusgadev。  舊數據庫SCHEMA文件的名稱為cusold.sql。  新數據庫SCHEMA文件的名稱為cusnew.sql。  輸出的卸出SCHEMA有改變的表的數據的SQL腳本文件名稱為unload.sql。  DB2數據庫SCHEMA同步步驟  1、從SIT環境中取得最新的數據庫SCHEMA。  2、從單元測試環境取得舊數據庫的SCHEMA。  3、在單元測試環境,用db2move命令卸出舊數據庫的數據。  4、比較兩個版本的異同。  5、假如沒有任何表的SCHEMA發生了改變,則執行第7步。  6、假如有表的SCHEMA發生了改變,則執行:  用新的表結構創建一個臨時表;  生成insert into transtmptbl (...) select ... from 的SQL;  將臨時表中的數據導出到文件中;  刪除臨時表;  用新的數據替換第3步導出的指定表的數據文件,然后執行第7步。  7、取得新SCHEMA的表空間名稱。  8、重建數據庫。  9、有選擇的將新庫中獨有的表的數據導入到本地新數據庫中。  10、檢查數據庫的完整性。  以下,我們具體說明這些步驟。  從SIT環境中取得最新的數據庫SCHEMA。在SIT環境中,執行以下命令: 上一頁1234567下一頁 db2look -d cusgadev -i db2admin -w
db2admin -e -a -o cusnew.sql
  該命令用于從SIT環境中抽取最新的DDL語句。其中各選項的涵義如下:  -d :指定被抽取DDL的數據庫名稱。  -e:抽取數據庫的DDL語句,包括表、視圖、自動摘要表、別名、索引、觸發器、Sequences、User defined Distinct Types、PRimary Key/RI/CHECK約束、用戶定義的結構化類型、用戶定義的函數、用戶定義的方法、用戶定義的轉換。  -i :連接遠程數據庫時,需要用這個選項指定登錄用戶名。  -w :連接遠程數據庫時,需要用這個選項指定登錄用戶的密碼。  -a:輸出所有用戶創建的對象,而不僅僅是當前登錄用戶創建的對象。  -o :將DDL輸出到指定的文件中。假如不指定該選項,則將輸出到標準輸出。  從單元測試環境取得舊數據庫的SCHEMA。在單元測試環境中,執行以下命令:  db2look -d cusgadev -e -a -o cusnew.sql  該命令用于從單元測試環境中抽取最新的DDL語句。各選項的涵義見上文。  在單元單元測試環境,卸出舊數據庫的數據。在單元測試環境中,執行以下命令:  db2move cusgadev export  該命令用于將單元測試環境中已有的數據輸出到當前目錄下。該命令為每一個表生成獨立的PC/IXF格式的數據文件,這些文件可以傳輸到任何其他的機器上并通過load或者import命令裝入到那臺機器上的DB2數據庫中。  該命令同時生成一個名為"db2move.lst"的文件,這個文件是卸出表的清單,指明哪一個表對應到哪一個數據文件。該文件將用于之后的步驟,以便用最新的SCHEMA卸出原有表的數據。  分析新舊數據庫SCHEMA  以下,我們使用cygwin環境下的SHELL程序來分析新舊數據庫的SCHEMA。 上一頁12345678下一頁   格式化SCHEMA文件  為了比較新舊數據庫的SCHEMA,我們需要將兩個SCHEMA文件轉換成統一格式,包括:將所有大寫替換成小寫;刪除所有行首的空格;將多個空格合并成1個空格。其中,空格包括制表符(Tab)和空格字符(Space)。  使用以下命令組合格式化SCHEMA文件:sed -e "s/^[  ]*//"
  -e "s/[   ][   ]*/ /g"
  ${OLDDBSCHEMA} | tr [:upper:] [:lower:] > ${OLDDBSCHEMATMP}
  取得新舊數據庫的table清單  定義如下函數,從數據庫的SCHEMA文件中取得其中的table清單。這個函數適用于由db2look生成的、DB2數據庫的DDL文件。  # 根據數據庫的SCHEMA文件,取得其中的table清單。  # $1. 數據庫的SCHMEA文件。  # $2. 輸出的table清單文件。gettbllist()
{
    grep -i "^[   ]*create[    ][   ]*table" $1 > $2.tmp
    sed -e "s/^[  ]*CREATE[    ][   ]*TABLE//"
      -e "s/(.*$//"
      $2.tmp | sort > $2
    rm $2.tmp
}
  找出僅在舊庫或者僅在新庫獨有的表  定義如下函數,取出僅在指定數據庫SCHEMA中存在的table的清單。這個函數適用于由db2look生成的、DB2數據庫的DDL文件。  # 取出僅在第一個參數指定的數據庫SCHEMA中存在的表的名稱清單  # $1: 待分析的數據庫SCHEMA文件  # $2: 用作參照的數據庫SCHEMA文件  # $3: 屏幕輸出的提示信息gettableonlyinone()
{
  if [ $# -eq 3 ]
  then
    echo $3
  fi
  TABLEINBOTH=""
  for tblname in `awk -F"." '{printf("%s
", $2);}' $1 | awk -F"""
  '{printf("%s ", $2)}' | sort`
  do
    grep -i ""$tblname"" $2 1>/dev/null 2>&1
    if [ ! $? -eq 0 ]
    then
      if [ $# -eq 3 ]
      then
        echo $tblname
      fi
    else
      TABLEINBOTH="${TABLEINBOTH} ${tblname}"
    fi
  done
}
上一頁123456789下一頁   對于僅在舊數據庫中存在的表,需要從db2move.lst中刪除該表對應的行。對于僅在新數據庫中存在的表,需要根據需要有選擇的從新數據庫中卸出數據并裝入到新數據庫中。找出結構不同的表,并生成卸出數據的SQL腳本。  通過以下步驟,找到在新舊數據庫中都存在,并且結構發生了變化的table,并生成重新卸出數據的SQL語句。  # 根據數據庫的SCHEMA文件,取得指定table的SCHEMA  # $1: table名稱  # $2: 數據庫的SCHEMA文件,需要先做格式化  # $3: 輸出的表的SCHEMA文件gettableschema()
{
#echo "table name: " $1
#echo "dbschema name: " $2
#echo "outfile name: " $3
awk -v_tblname=$1 'BEGIN{isThisTable = 0;}{
if($1 == "create" && $2 == "table"
&& match($0, """_tblname""") > 0)
{
isThisTable = 1;
printf("create table %s (
", _tblname); #### )}
else if(isThisTable == 1)
{
if(match($0, ";") > 0)
{
isThisTable = 0;
if($1 == "in")
printf(";
", $0);
else
printf("%s
", $0);
}
else if(match($0,
"timestamp not null with default ,") > 0)
{
printf("%s timestamp not null
with default current timestamp ,
", $1);
}
else
{
printf("%s
", $0);
}
}
}' $2 > $3
}
上一頁12345678910下一頁   # 生成卸出指定表的數據的SQL腳本  # $1. 舊數據庫的SCHEMA文件  # $2. 新數據庫的SCHEMA文件  # $3. 輸出的卸出指定表的數據的SQL腳本文件名  # $4. 指定的表名  # $5. db2move卸出文件時的清單文件genunloadsql()
{
TMPSQLFILE=.tmpsql.sql.sql
TMPNEWTBLFLD=.tmpfld.fld.fld
rm -f ${TMPSQLFILE}
# 1. 用新的表結構創建一個臨時表
awk '{
if(NR > 1)
{
gsub(""", "", $1); # remove character "
printf("%s
", $0);
}
else
{
printf("create table sihitranstmptbl (
"); # )
}
}' $2 > ${TMPSQLFILE}
# 2. 生成insert into transtmptbl (...) select ... from <oldtbl>的SQL
# 2.1. 生成新舊兩個表的字段列表
awk '{
if(NR > 1 && $1 != ";")
{
gsub(""", "", $1); # remove character "
printf("%s
", $1);}
}' $2 > ${TMPNEWTBLFLD}
isFirstFeild=1
Select=""
Into=""
for fldname in `cat ${TMPNEWTBLFLD}`
do
grep ""${fldname}"" $1 1>/dev/null 2>&1
if [ $? -eq 0 ]
then
# 2.2. 取出在新舊兩表中都有的字段名,加入到select子句和into子句中
if [ ${isFirstFeild} -eq 0 ]
then
Select="${Select},"
Into="${Into},"
fi
Select="${Select} ${fldname}"
Into="${Into} ${fldname}"
isFirstFeild=0
else
# 2.3. 取出僅在新表中出現的字段,假如該字段不答應null,
# 且沒有設置default值,
則按以下原則取默認值放到select子句中,
# 并將字段名放到into子句中
grep ""${fldname}"" $2 |
grep "not null" 1>/dev/null 2>&1
if [ $? -eq 0 ]
then
grep ""${fldname}"" $2
| grep "with default" 1>/dev/null 2>&1
if [ ! $? -eq 0 ]
then
if [ ${isFirstFeild} -eq 0 ]
then
Select="${Select},"
Into="${Into},"
fi
# 計算默認值
# 對于新增的字符型字段,默認值為'';
# 對于新增的數值型字段,默認值為0;
# 對于新增的TIMESTAMP字段,默認值為'';
# 對于新增的SERIAL開字段,默認值為0;
# 對于新增的DATE字段,默認值為;
# 對于新增的DATETIME字段,默認值為;
Const=`grep ""${fldname}"" $2 | awk '{
if(match($2, "int") > 0) # integer, smallint, bigint
printf("0");
else if(match($2, "numeric") > 0)
printf("0.0");
else if(match($2, "decimal") > 0)
printf("0.0");
else if(match($2, "double") > 0)
printf("0.0");
else if(match($2, "float") > 0)
printf("0.0");
else if(match($2, "real") > 0)
printf("0.0");
else if(match($2, "char") > 0) # char, varchar
printf("" "");
else if($2 == "timestamp")
printf("current timestamp");
else if($2 == "date")
printf("current date");
else if($2 == "time")
printf("current time");
else
printf("" "");
}'`
Select="${Select} ${Const}"
Into="${Into} ${fldname}"
isFirstFeild=0
fi
fi
fi
done
tablefullname=`grep -i ""$4"" $5
| awk -F"!" '{printf("%s", $2);}'`
echo "insert into sihitranstmptbl
(${Into}) select ${Select} from
${tablefullname} ;" >> ${TMPSQLFILE}
# 3. 將臨時表中的數據導出到文件中
Unloadfile=`grep -i ""$4"" $5 |
awk -F"!" '{printf("%s", $3);}'`
echo "export to ${Unloadfile}
of ixf select * from sihitranstmptbl ;"
>> ${TMPSQLFILE}
# 4. 刪除臨時表
echo "drop table sihitranstmptbl ;"
>> ${TMPSQLFILE}
cat ${TMPSQLFILE} >> $3
rm -f ${TMPSQLFILE}
rm -f ${TMPNEWTBLFLD}
}
echo "table in both database:"
TABLEINBOTH="`echo ${TABLEINBOTH}
| tr [:upper:] [:lower:]`"
echo > ${UNLOADSQLFILE}
for tblname in ${TABLEINBOTH}
do
gettableschema ${tblname}
${OLDDBSCHEMATMP} ${OLDTBLSCHEMA}
gettableschema ${tblname}
${NEWDBSCHEMATMP} ${NEWTBLSCHEMA}
diff ${OLDTBLSCHEMA}
${NEWTBLSCHEMA} 1>/dev/null 2>&1
if [ ! $? -eq 0 ]
then
# 假如有不同,則生成卸出數據的SQL腳本
echo "different table:" ${tblname}
genunloadsql ${OLDTBLSCHEMA} ${NEWTBLSCHEMA}
${UNLOADSQLFILE} ${tblname} ${DB2MOVELISTFILE}
else
echo "same table:" ${tblname}
fi
done
上一頁234567891011下一頁   其中,TABLEINBOTH是由上一步(找出僅在舊庫或者新庫中獨有的表)的副產品。  注重,上述程序中,并沒有處理新舊table中均有并且字段類型不同的字段,這種情況可以在卸出數據時按需要手工編輯生成的SQL腳本。  生成的SQL腳本名稱叫"unload.sql"。在PC機上的DB2命令窗口中執行:db2 -z result.txt -tvf unload.sql  其中,"-z"選項將執行結果同時輸出到屏幕及文件result.txt中。執行結束時,需要查看result.txt,假如其中有錯誤提示,請按需要修改unload.sql。修改之后,再重新執行上述命令,直到所有SQL命令均執行無錯為止。  取得新SCHEMA的表空間名稱  通過以下步驟,找出新數據庫使用的表空間的名稱,并給出創建數據庫緩沖池及表空間的SQL的建議。  # 8. 根據新數據庫SCHEMA文件取得tablespace的名稱清單  # 并給出創建緩沖池及tablespace的SQL建議echo "創建緩沖池的命令: "
echo "create bufferpool BF81 size 10000 pagesize 8 K"
echo "創建表空間的命令: "
echo "------------------------------------
--------------------------"
for tblspace in ` grep -i "^[   ]*in[   ]" ${NEWDBSCHEMA} | grep ";" | awk '{
printf("%s
", $2);
if(NF > 3)
{
if($3 == "INDEX" && $4 == "IN")
{
printf("%s
", $5);
}}
}' | sort | uniq `
do
echo "CREATE TABLESPACE ${tblspace} PAGESIZE 8K MANAGED BY DATABASE USING
(FILE '<filename>' 50000) bufferpool bf81"
done
echo "-----------------------------------
---------------------------"
上一頁34567891011下一頁 執行結果類似于:  創建緩沖池的命令:create bufferpool BF81 size 10000 pagesize 8 KB。  創建表空間的命令:--------------------------------------
------------------------
CREATE TABLESPACE "DATATBS00_8K" PAGESIZE
8K MANAGED BY DATABASE USING (FILE
'<filename>' 50000) bufferpool bf81
CREATE TABLESPACE "DATATBS01_8K" PAGESIZE
8K MANAGED BY DATABASE USING (FILE
'<filename>' 50000) bufferpool bf81
CREATE TABLESPACE "DATATBS02_8K" PAGESIZE
8K MANAGED BY DATABASE USING (FILE
'<filename>' 50000) bufferpool bf81
CREATE TABLESPACE "IDXTBS00_8K" PAGESIZE
8K MANAGED BY DATABASE USING (FILE
'<filename>' 50000) bufferpool bf81
CREATE TABLESPACE "IDXTBS02_8K" PAGESIZE
8K MANAGED BY DATABASE USING (FILE
'<filename>' 50000) bufferpool bf81
CREATE TABLESPACE "STATICTBS00_8K" PAGESIZE
8K MANAGED BY DATABASE USING
(FILE '<filename>' 50000) bufferpool bf81
CREATE TABLESPACE "USERSPACE1" PAGESIZE
8K MANAGED BY DATABASE USING (FILE
'<filename>' 50000) bufferpool bf81
------------------------------------
--------------------------
  在實際創建表空間時,需要將其中的""替換成Windows系統下的一個文件名稱,每一個表空間使用不同的文件名。也可以根據對數據庫中數據分布的估計,調整表空間的大小。 上一頁4567891011下一頁   重建數據庫  按以下步驟重建數據庫:  1、編輯db2move.lst,刪除在新庫中已不使用的表。  根據上述步驟中得到的僅在舊數據庫中存在的表,編輯db2move.lst,刪除該表所在的行。  2、刪除舊數據庫。  執行以下命令,刪除舊數據庫:db2 drop database cusgadev  3、創建數據庫,執行以下命令,創建新數據庫:  db2 create database cusgadev using codeset iso8859-1 territory cn  其中,"iso8859-1"表示數據庫使用的字符集,"cn"表示數據庫使用的地域。  4、連接數據庫:執行以下命令,連接新數據庫:db2 connect to cusgadev  5、修改物理日志參數,執行以下命令,修改數據庫的日志參數:  db2 update database configuration using logfilsiz 25000 deferred  創建數據時,默認的日志空間比較小,對于大事務的處理有影響,所以,需要根據應用的需要及PC機的配置適當調整日志空間的值。  可以使用"GET DATABASE CONFIGURATION"命令查看數據庫的當前配置。  6、創建緩沖池,執行以下命令,為數據庫創建緩沖池:db2 create bufferpool BF81 size 10000 pagesize 8 K。  7、創建表空間,執行以下命令,為數據庫創建表空間:db2 CREATE TABLESPACE "DATATBS00_8K" PAGESIZE
8K MANAGED BY DATABASE USING
(FILE '<filename>' 50000) bufferpool bf81
db2 CREATE TABLESPACE "DATATBS01_8K" PAGESIZE
8K MANAGED BY DATABASE USING
(FILE '<filename>' 50000) bufferpool bf81
db2 CREATE TABLESPACE "DATATBS02_8K" PAGESIZE
8K MANAGED BY DATABASE USING
(FILE '<filename>' 50000) bufferpool bf81
db2 CREATE TABLESPACE "IDXTBS00_8K" PAGESIZE
8K MANAGED BY DATABASE USING
(FILE '<filename>' 50000) bufferpool bf81
db2 CREATE TABLESPACE "IDXTBS02_8K" PAGESIZE
8K MANAGED BY DATABASE USING
(FILE '<filename>' 50000) bufferpool bf81
db2 CREATE TABLESPACE "STATICTBS00_8K" PAGESIZE
8K MANAGED BY DATABASE USING
(FILE '<filename>' 50000) bufferpool bf81
db2 CREATE TABLESPACE "USERSPACE1" PAGESIZE
8K MANAGED BY DATABASE USING
(FILE '<filename>' 50000) bufferpool bf81
上一頁567891011下一頁 其中,tablespace的名稱是從新數據庫的SCHEMA文件中提取出來的。本例中,它們都使用同一個緩沖池。""需要按照PC機硬盤空余空間的情況,修改為實際的全路徑文件名稱。  8、用新的SCHEMA創建數據庫:  執行以下命令,按照新數據庫的SCHEMA創建其中的各種對象,如表、索引等:db2 -tvf cusnew.sql。  9、裝入數據,執行以下命令,將舊數據庫的數據裝入到剛創建的新數據庫中:db2move cusgadev load。  該命令使用的修改后的db2move.lst作為裝入表的清單。  有選擇的將新庫中獨有的表的數據導入到本地新數據庫中對于僅在新數據庫中存在的表,可以根據需要有選擇的將其數據從SIT環境導入到單元測試環境。本文中,不考慮新表對于其他表的外鍵關聯。  假設某個僅在新數據庫中存在的表的名稱為"newtable",在SIT環境執行以下命令卸出數據:  db2 unload to newtable.ixf of ixf select * from newtable。將文件“newtable.ixf”傳輸到單元測試環境所在的PC機上,執行以下命令:db2 load from newtable.ixf of ixf insert into newtable。假如這個新表對于其他表有外鍵關聯,還需要導入其他相關表的數據。  檢查數據庫的完整性  檢查完整性的SHELL程序以下是"CheckIntegrity.sh"的源代碼。該程序用于在數據load結束以后,檢查數據庫的完整性。#!/usr/bin/sh
# 在數據load結束后,檢查數據庫的完整性
# Copyright: SI HITECH 2006
# 作  者: 鄭靖華
# 創建日期: 2006 年 8 月 2 日
# 指定數據庫名稱
if [ $# -lt 1 ]
then
  DBNAME=ccdb
else
  DBNAME=$1
fi
# 檢查db2move的lst文件
if [ ! -r db2move.lst ]
then
  echo "當前目錄下沒有db2move的清單文件
[ db2move.lst ],請確保目錄正確并再次執行本命令!"
  exit 1
fi
# 生成執行完整性檢查的SHELL程序
awk -F"!" -v_dbname=${DBNAME} 'BEGIN{
  printf("connect to %s;
", _dbname);
}{
  printf("set integrity for %s immediate checked;
", $2);
}' db2move.lst > $DBNAME.integrity.sql
# 執行檢查程序
db2 -tvf $DBNAME.integrity.sql
echo "完整性檢查完畢,請仔細查看檢查結果!"
exit 0
上一頁67891011下一頁
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 鹤峰县| 江华| 崇左市| 林西县| 全南县| 南丰县| 兴义市| 庆阳市| 加查县| 革吉县| 元阳县| 崇明县| 绿春县| 杂多县| 永安市| 青川县| 慈溪市| 宿州市| 绥宁县| 绩溪县| 滦南县| 新乐市| 桦川县| 静乐县| 淄博市| 嫩江县| 曲松县| 大城县| 高雄市| 定安县| 清河县| 芜湖县| 邹平县| 罗山县| 崇礼县| 太湖县| 秦皇岛市| 江门市| 杨浦区| 汶上县| 新闻|