年初的時候一直在做一個網站MSSQL2000->MySQL5的遷移工作,因爲採用了不同的程序系統,所以主要問題在數據的遷移。由於2個系統數據庫結構差異非常大,不方便採取SQLSERVER裏導入MYSQL的ODBC數據源的功能(也不推薦這麼做,字段類型等不同點會搞死人的~),因此就在WINDOWS下自己寫PHP腳本從SQLSERVER裏讀數據,然後按照新系統的需要處理之後插入MYSQL裏面,靈活也比較方便。實際過程主要有下面幾個問題:
1、數據庫的連接,主要是連接SQLSERVER。主要有3種方法:
1.1利用PHP中的mssql_系列函數,這個與使用mysql_系列函數類似,不過要打開php.ini中相關擴展(extension=php_mssql.dll)。
1.2利用ODBC連接,由於抽象了具體數據庫,所以沒有辦法利用數據表字段名=>數組鍵名的特性,在針對具體應用時不是很方便,代碼形式:
$conn=odbc_connect("datasource","username","password");
$sql="select*fromnews";
$cur=odbc_exec($conn,$sql);
while(odbc_fetch_row($cur)){
$field1=odbc_result($cur,1);
$field2=odbc_result($cur,2);
//dosomething
}
1.3使用PDO-PHP5中加入數據對象抽象層,作爲官方推出的數據訪問接口,優點有很多,比如支持參數綁定以防止SQL注入;對於不同數據庫加載不同驅動即可,程序代碼是一致的,便於移植等等,相信應該是大勢所趨。不過由於用了PHP5全新的面向對象特性,需要PHP5的支持,5.1可以直接使用,5需要裝PECL,另外還要修改PHP.ini,增加:extension=php_pdo_mysql.dll和extension=php_pdo_mssql.dll,實際代碼如下:
try{
$DBH=newPDO("mssql:dbname=XXX;host=localhost",
"root","password");//ConnecttoDB
}catch(PDOException$e){
print"Error!:".$e->getMessage();//ErrorMessage
die();
}
$stmt=$DBH->prepare("SELECT*FROMnews");//StmtHandle$stmt
if($stmt->execute()){
while($row=$stmt->fetch()){
//dosomething
}
}
$stmt2=$mssql->prepare("INSERTINTOnews
(title,author)VALUES(:title,:author)");
$stmt2->bindParam(':title',$title);
$stmt2->bindParam(':author',$author);
$stmt2->execute();
$DBH=null;//CloseConnection這裏要提醒下的是MSSQL裏面是沒有MYSQL中LIMIT這個語法的。
2、TEXT字段被截斷的問題。
上面嘗試了3種連接數據庫方法,是因爲當初連上MSSQL後SELECT出來的數據總是隻有4K長度,以爲是連接方式限制導致的,所以換了幾種都是這樣,最後查了資料才知道,是php.ini裏面這2句配置的問題:
;Validrange0-2147483647.Default=4096.
mssql.textlimit=4096
;Validrange0-2147483647.Default=4096.
mssql.textsize=4096
把4096改成-1(代表無限制)即可,也可以使用mssql_query("SETTEXTSIZE65536");來實現。
3.兩種數據庫字段類型不同的問題有2個地方需要講一下,一個是字段支持最大長度要注意,以免插入數據庫時候被截斷,另外一個就是日期格式的問題了,我比較喜歡用UNIX時間戳。在連MSSQL時候可以用"selectunix_timestamp(created)fromnews"來實現MSSQL裏面DATETIME到MYSQL裏時間戳的轉換。不過遷移時候一次要提取表中所有字段,像上面這種方法就沒有簡單的"select*fromnews"簡潔,需要羅列所有字段。實際可以直接SELECT出來,得到的是一個字符串,比如在MSSQL裏面是2006-01-0112:01,取出來的字符串是"2006一月0112:01"(有些奇怪,不知道爲什麼會產生中文)。用下面這個函數可以轉換成時間戳:
functionConvertTime($timestring){
if($timestring==null){
return 0;
}
$time=explode("",$timestring);
$year=$time[0];
switch($time[1]){
case"一月":$month="1";break;
case"二月":$month="2";break;
case"三月":$month="3";break;
case"四月":$month="4";break;
case"五月":$month="5";break;
case"六月":$month="6";break;
case"七月":$month="7";break;
case"八月":$month="8";break;
case"九月":$month="9";break;
case"十月":$month="10";break;
case"十一月":$month="11";break;
case"十二月":$month="12";break;
default:break;
}
$day=$time[2];
$h=0;
$m=0;
$s=0;
if(!empty($time[3])){
$time2=explode(":",$time[3]);
$h=$time2[0];
$i=$time2[1];
}
//returndate("Y-m-dH:i:s",mktime($h,$i,$s,$month,$day,$year));
returnmktime($h,$i,$s,$month,$day,$year);
}
最後轉換腳本寫完了可以在CMD窗口裏面用php.exeabc.php來執行,這種方式是沒有超時時間的,適合遷移大批量數據。
基本上就是這些內容,希望對大家有幫助。
Update(06/05/05):關於時間戳的轉換,在php.ini中加上
mssql.datetimeconvert=Off
後就能得到類似2006-01-0112:01不帶有中文的格式了。