數據庫數據修復

簡要記錄背景:

1. 數據庫由於硬盤問題完整性被破壞了,使用dbcc checkdb完全沒有效果

2. 經檢查發現,有兩張使用最頻繁的表無法進行任何操作,其他表正常

3. 通過某數據庫修復工具,可以查看到那兩張壞掉的表中的數據【估計還是不全】,但由於沒有授權,只能查看,數據導不出來

 

在此基礎上,我們按如下辦法來儘可能對數據庫進行修復,修復辦法如下:

1. 想辦法重建立一個新庫,除了兩張壞掉的表,其他表以複製的形式重建

由於壞的表無法刪除,導致整個庫都無法使用,我們只能將好的數據進行轉移,重建數據庫。

我們在將表結構建立好後,使用如下腳本,生成了庫中所有需要導入的表的記錄

use Charge
DECLARE @TableName varchar(255);
DECLARE @ColumnName varchar(255);
DECLARE @ColumnNames varchar(2550);
declare @currentDbName varchar(255)
declare @sourceDbName varchar(255)
set @currentDbName = 'newdb'
set @sourceDbName = 'brokendb'

DECLARE Table_Cursor CURSOR FOR SELECT [name] FROM sysobjects WHERE xtype='U';
 OPEN Table_Cursor;
FETCH NEXT FROM Table_Cursor INTO @TableName;
  WHILE(@@FETCH_STATUS=0)
  BEGIN
  if(@TableName <> 'Tbl_Customer' and @TableName <> 'Tbl_Company' )
begin
 print '/*---------------------------------------------------------------'
 print @TableName
 print '---------------------------------------------------------------*/'
 begin
 set @ColumnNames = ''
  DECLARE Column_Cursor CURSOR FOR select name from syscolumns where id=object_id(@TableName)
OPEN Column_Cursor;
FETCH NEXT FROM Column_Cursor INTO @ColumnName;
WHILE(@@FETCH_STATUS=0)
begin
set @ColumnNames = @ColumnNames + '[' + @ColumnName + ']' + ','
FETCH NEXT FROM Column_Cursor INTO @ColumnName;
end
 CLOSE Column_Cursor
 DEALLOCATE Column_Cursor; 
  end  
set @ColumnNames = left(@ColumnNames, len(@ColumnNames) -1)
print 'use ' + @currentDbName
print 'begin try'
print 'Set IDENTITY_INSERT ' + @TableName + ' ON'
print 'truncate table ' + @TableName
print 'INSERT INTO ['+ @currentDbName +'].[dbo].[' + @TableName + '](' + @ColumnNames + ') select ' + @ColumnNames + ' from [' + @sourceDbName + '].[dbo].[' + @TableName + ']'
print 'end try'
print 'begin catch'
print 'print ''' + @TableName + ' run error'''
print 'end catch'
print 'begin try'
print 'Set IDENTITY_INSERT ' + @TableName + ' OFF'
print 'end try'
print 'begin catch'
print 'end catch'
end
  FETCH NEXT FROM   Table_Cursor INTO @TableName;
 END
 CLOSE Table_Cursor;
 DEALLOCATE Table_Cursor; 
GO


2. 執行上述腳本,生成了可以導入整個庫中想要的表的數據,自動生成的腳本如下:

/*---------------------------------------------------------------
Tbl_Order
---------------------------------------------------------------*/
use newdb
begin try
Set IDENTITY_INSERT Tbl_Order ON
truncate table Tbl_Order
INSERT INTO [newdb].[dbo].[Tbl_Order]([OrderId],[EuId],[CardId]) select [OrderId],[EuId],[CardId] from [brokendb].[dbo].[Tbl_Order]
end try
begin catch
print 'Tbl_Order run error'
end catch
begin try
Set IDENTITY_INSERT Tbl_Order OFF
end try
begin catch
end catch
/*---------------------------------------------------------------
Tbl_CancelCharge
---------------------------------------------------------------*/
use newdb
begin try
Set IDENTITY_INSERT Tbl_CancelCharge ON
truncate table Tbl_CancelCharge
INSERT INTO [newdb].[dbo].[Tbl_CancelCharge]([CancelId],[EuId],[ECharacterID],[Type],[Num],[CreateDate]) select [CancelId],[EuId],[ECharacterID],[Type],[Num],[CreateDate] from [brokendb].[dbo].[Tbl_CancelCharge]
end try
begin catch
print 'Tbl_CancelCharge run error'
end catch
begin try
Set IDENTITY_INSERT Tbl_CancelCharge OFF
end try
begin catch
end catch


 

3. 通過SPY++監視發現,原來第三方的數據庫修復軟件是通過系統的 SysListView32 來顯示的數據庫數據,這樣我們就可以利用讀取外部進程控件數據的辦法,將其能讀取的數據讀取出來,獲取其窗口句柄及讀取行列數據的代碼分別如下:

 

/************************************************************************/
/*                                                                      */
/************************************************************************/
HWND CWindowFind::GetChildWindow(HWND hwnd,int iIndex)
{
	HWND hwndChind = NULL;
	CString strTemp = "";
	int i = 1;
	hwndChind = GetWindow(hwnd,GW_CHILD);
	CWnd *pWnd = CWnd::FromHandle(hwndChind);
	while (pWnd)
	{	
		hwndChind = pWnd->GetSafeHwnd();
		if (i == iIndex)
		{
			return hwndChind;
		}
		pWnd = pWnd->GetNextWindow(GW_HWNDNEXT);
		i++;
	}
	return hwndChind;
}
接下來找到列表句柄及獲取行數:

HWND hwndParent = ::FindWindow(NULL, "MSSQL數據庫修復大師 專業版");
		hwndParent = gl_find.GetChildWindow(hwndParent, 1);
		hwndParent = gl_find.GetChildWindow(hwndParent, 2);
		HWND hwnd = gl_find.GetChildWindow(hwndParent, 1);
		int nTotalCount = (int) ::SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0L);

獲取某行列的字符串:

CString CCListCtrlExportDlg::GetListItemText(HWND hwnd,int iItem,int iSubItem)
{
	LVITEM lvitem, *plvitem;
	char ItemBuf[512],*pItem;
	DWORD PID;
	HANDLE hProcess;
	CString strRet = "";
	GetWindowThreadProcessId(hwnd, &PID);
	hProcess=OpenProcess(PROCESS_ALL_ACCESS,false,PID);
	if (!hProcess)
	{
		return "";
	}	
	plvitem=(LVITEM*)VirtualAllocEx(hProcess, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE);
	pItem=(char*)VirtualAllocEx(hProcess, NULL, 512, MEM_COMMIT, PAGE_READWRITE);
	if ((!plvitem)||(!pItem))
	{
		CloseHandle(hProcess);
		return "";
	}
	else   
	{
		lvitem.cchTextMax=512;
		lvitem.iSubItem=iSubItem;
		lvitem.pszText=pItem;
		WriteProcessMemory(hProcess, plvitem, &lvitem, sizeof(LVITEM), NULL);
		::SendMessage(hwnd,LVM_GETITEMTEXT, (WPARAM)iItem,(LPARAM)plvitem);
		ReadProcessMemory(hProcess, pItem, ItemBuf, 512, NULL);
		strRet.Format("%s",ItemBuf);
	}			
	VirtualFreeEx(hProcess, plvitem, 0, MEM_RELEASE);
	VirtualFreeEx(hProcess, pItem, 0, MEM_RELEASE);
	CloseHandle(hProcess);
	return strRet;
}
這樣每一行每一列的值已經都可以拿到了,接下來只需要將讀取到的數據組合成相應的SQL腳本,再到查詢分析器中執行,即可將丟失的數據插入到數據庫中。【這裏我導出成文本文件,再導入到SQL SERVER中時,遇到一些時間格式問題,所以直接使用SQL】

通過以上步驟,一個完整的數據庫已經得到複製,並且將丟失的部分數據找回。【有些數據還是丟失了,在第三方軟件上也沒有顯示】



 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章