程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> DB2數據庫 >> DB2教程 >> 用AWK實現DB2 數據庫 Schema的同步

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

編輯:DB2教程

在多個成員用一個系統進行集成測試時,每一個成員 PC 機上也要安裝一個相同的數據庫作為單元測試環境。本文介紹了保持各個數據庫一致性——我們稱這個過程為數據庫 schema 的同步——的幾種方式。

場景說明

我們在項目中經常遇到這樣一種情況:項目組所有成員共用一個系統集成測試環境(SIT)中的數據庫,每一個成員PC機上也安裝一個相同的數據庫作為單元測試環境。因為業務模型的變化,導致數據庫結構發生變化時,通常由數據庫管理員根據數據模型組的需求修改SIT的數據庫結構,並保持原有數據的延續性。此時,PC機上單元測試數據庫結構與SIT數據庫結構就可能不一致,通常有以下幾種方式來繼續保持它們的一致性(我們稱這個過程為數據庫SCHEMA的同步):

1、 由模型組或者數據庫管理員發布數據庫修改的命令清單,各成員按照清單逐步操作,實現數據庫SCHEMA的同步。這種方法要求每一次SIT數據庫SCHEMA的修改都必須被記錄在案,並通知到項目組每一個成員。如果某個成員遺漏了其中某一次修改,則他以後的修改都可能會有問題。當然,他也可以從其他成員的單元測試環境中備份、恢復最新版的數據庫。

2、 由數據庫管理員將SIT數據庫整庫備份,各成員在PC機上刪除原有數據庫,恢復該備份數據庫。這種方法看起來總能得到最新的SCHEMA和數據,但通常比較難於實施。因為SIT環境通常在UNIX環境下,而單元測試環境通常在Windows環境下,二者對於磁盤設備的管理方式相差甚大,通過數據庫備份工具得到的備份文件,在不同操作系統下恢復時,對於磁盤設備不同導致的修改相當麻煩。同時,SIT環境的數據量通常比較大,有的項目甚至於會定期從生產線上獲取最新的數據,而單元測試環境通常是在PC機上,所能提供的磁盤空間相對較小,多數情況下都不足以恢復全量的SIT數據庫。

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環境中,執行以下命令: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。

格式化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
}

對於僅在舊數據庫中存在的表,需要從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
}

其中,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 "-----------------------------------
---------------------------"執行結果類似於:

創建緩沖池的命令: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系統下的一個文件名稱,每一個表空間使用不同的文件名。也可以根據對數據庫中數據分布的估計,調整表空間的大小。

重建數據庫

按以下步驟重建數據庫:

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其中,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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved