1. 程式人生 > >【轉】Sqlserver通過連結伺服器訪問Oracle的解決辦法

【轉】Sqlserver通過連結伺服器訪問Oracle的解決辦法

一、建立sqlserver連結服務(sqlserver連結oracle)

 首先sqlserver 連結oracle可以通過兩個訪問介面:

“MSDAORA” 和“OraOLEDB.Oracle”

1、“MSDAORA”訪問介面是由Microsoft OLE DB Provider for Oracle提供的,這裡建議不使用此介面進行連結。通過該訪問介面建立的連結伺服器在進行查詢oracle表(帶資料型別CLOB、BLOB欄位)時會報這個錯誤

“連結伺服器""的 OLE DB 訪問介面 "MSDAORA" 返回了訊息 "發生了一個 Oracle 錯誤,但無法從 Oracle 中檢索錯誤資訊。"。
連結伺服器""的 OLE DB 訪問介面 "MSDAORA" 返回了訊息 "資料型別不被支援。"。
訊息 7321,級別 16,狀態 2,第 1 行
準備對連結伺服器 "" 的 OLE DB 訪問介面 "MSDAORA" 執行查詢"select * from SYS_MESSAGE"時出錯。”

連結伺服器 "LINK2ORACLE" 的 OLE DB 訪問介面 "MSDAORA" 為列提供的元資料不一致。物件 ""CMCC"."OS2_GIS_CELL"" 的列 "ISOPENED" (編譯時序號為 20)在編譯時有 130 的 "DBTYPE",但在執行時有錯。

2、“OraOLEDB.Oracle” 訪問介面是由oracle 的Oracle Probider for OLE DB 驅動提供的。它解決了兩個資料庫型別不一致的的問題。而且如果需要使用分散式事務,必須使用它來建立連結伺服器。後文會有詳細介紹。
在建立之前,在SQLSERVER中,連結伺服器->訪問介面->OraOLEDB.Oracle->右鍵屬性,選中 "Allow inprocess" (中文為:允許程序內)

這一步是使我們選擇的OraOLEDB.Oracle介面開啟執行操作。如未設定會報如下錯誤:
 “無法初始化連結伺服器 "null" 的 OLE DB 訪問介面 "OraOLEDB.Oracle" 的資料來源物件"


使用Oracle Probider for OLE DB 驅動建立sqlserver連結伺服器的程式碼:

 1  --建立資料庫連結伺服器
 2  EXEC sp_addlinkedserver
 3  @server =N'OraclePolice', --要建立的連結伺服器別名
 4  @srvproduct=N'Oracle', --產品名稱
 5
@provider=N'OraOLEDB.Oracle', --OLE DB 驅動名稱 6 @datasrc=N'ORCL' --資料來源oracle"ora10g"network"admin"tnsnames.ora檢視 7 8 EXEC sp_addlinkedsrvlogin 9 'OraclePolice', --已建立的連結伺服器名 10 'false', -- 固定 */ 11 NULL, --為每個登陸SQL SERVER的使用者使用此連結伺服器,則寫使用者名稱*/ 12 'TESTDB', --帳號(oracle) 13 'TESTDB123' --密碼 14 15 exec sp_serveroption 'OraclePolice','rpc out','true' 16 exec sp_serveroption 'OraclePolice','rpc','true' 17 --這兩個是開啟rpc,rpc out的,預設為False,開啟後可以支援遠端更改分散式事務。(如有分散式事務操作必須要設定)

這樣我們就建好了連結伺服器,已經可以通過它對oracle資料庫進行查詢,這裡有兩種查詢方式。

1、SELECT * FROM OraclePolice..TESTDB.TABLE_TEST

(連結伺服器別名..Oracle名.oracle表,注意使用大寫)

這種方式可以進行操作,優點是使用簡單,一目瞭然,而缺點是效能太差,查詢大資料量表很慢。效率太差。

2、SELECT * FROM openquery(OraclePolice,'SELECT * FROM  TABLE_TEST')
經試驗,這種查詢方式速度幾乎和在Oralce中一樣快。並且我們可以將openquery() 當做表來用。例如
insert into openquery(OraclePolice,'SELECT * FROM TABLE_TEST')

values();--向oracle資料表插入資料
SELECT * FROM openquery(OraclePolice,'SELECT * FROM TABLE_TEST')

where TEST_NAME='' (TEST_NAME為TABLE_TEST表中的欄位)
故推薦這種查詢方式。

二、通過sqlserver連結伺服器呼叫oracle 儲存過程
在oracle裡資料庫裡寫了一個測試儲存過程,需要一個傳入引數和傳出引數。
下面是建立和呼叫這個儲存過程的程式碼:

 1  -- oracle 中建立儲存過程
 2  create or replace procedure A_TEST_NQ
 3  (
 4  namecode varchar2,
 5  namevalue out varchar2
 6  )
 7  is
 8  c varchar2(200);
 9  begin
10  c:='';
11  select NAME_VALUE into c FROM ALINK_SERVER_TEST WHERE NAME_CODE=namecode;
12  namevalue:=c;
13  end;
14  
15  -- ----------------------------------------------
16  -- 邪惡的分割線
17  -- ----------------------------------------------
18  
19  -- sqlserver 中呼叫儲存過程
20  declare @namecode varchar(200)-- 傳入引數
21  declare @namevalue varchar(5000)-- 傳出引數
22  
23  set @namecode='01'
24  -- 呼叫儲存過程
25  EXEC('begin A_TEST_PRC(?,?);end;',@namecode,@namevalue output) at OraclePolice

這裡要注意傳出引數,一定要加上Output,不然會報錯。

“連結伺服器"OraclePolice"的 OLE DB 訪問介面 "OraOLEDB.Oracle" 返回了訊息 "ORA-06502: PL/SQL: 數字或值錯誤 :  字串緩衝區太小
ORA-06512: 在 "SACON.A_TEST_NQ", line 11
ORA-06512: 在 line 1"。
訊息 7215,級別 17,狀態 1,第 6 行
無法在遠端伺服器 'OraclePolice' 上執行語句。”

三、通過sqlserver連結伺服器實現分散式事務

   許許多多的同行就是在這一步中躺下的,因為這一步配置繁瑣,同時和sqlserver、oracle資料庫版本,甚至是作業系統版本等都有關,驅除睡意,和我一步步來進行配置吧。

 

1、首先必須安裝好

Oracle Services For Microsoft Transaction Server

(版本與你的oracle版本一致)

它是ODAC中的一部分,因為oracle本身是不支援分散式事務的,通過這個驅動開放與微軟的事務服務。 我想絕大多數人配置好MSDTC並解析好名稱後仍會報“無法啟動分散式服務”就是因為這個驅動沒裝。

訊息 7391,級別 16,狀態 2,第 5 行
無法執行該操作,因為連結伺服器 "oracletest" 的 OLE DB 訪問介面 "OraOLEDB.Oracle" 無法啟動分散式事務。

 
2、必須用Oracle Probider for OLE DB 驅動提供的OraOLEDB.Oracle訪問介面來建立連結服務。(這個可能是因為microsoft提供的訪問介面並不存在oracle事務機制,所以只能通過oracle提供的訪問介面)


3、MSDTC設定。
   開啟"管理工具--元件服務",依次開啟"元件服務--計算機",在"我的電腦"上點選右鍵。在MSDTC選項卡中,點選"安全配置"按鈕,在安全配置視窗中做如下設定: 
    -->選中"網路DTC訪問"; 
    -->在客戶端管理中選中"允許遠端客戶端""允許遠端管理";
    -->在事務管理通訊中選"允許入站""允許出站""不要求進行驗證";
    -->保證DTC登陸賬戶為:NT Authority\NetworkService ;


4、雙方啟動MSDTC服務 
   MSDTC服務提供分散式事務服務,如果要在資料庫中使用分散式事務,必須

在參與的雙方伺服器啟動MSDTC(Distributed Transaction Coordinator)服務。


5、開啟雙方135埠
   MSDTC服務依賴於RPC(Remote Procedure Call (RPC))服務,RPC使用135埠,保證RPC服務啟動,如果伺服器有防火牆,保證135埠不被防火牆擋住。

 
6、在事務開始前加入set xact_abort ON語句
   對於大多數 OLE DB 提供程式(包括 SQL Server),必須將隱式或顯示事務中的資料修改語句中的 XACT_ABORT 設定為 ON。唯一不需要該選項的情況是在提供程式支援巢狀事務時。

 
7、伺服器名解析
  在建立連結伺服器時@server或者@datasrc設定為sql server伺服器名時,需要做名稱解析,就是把伺服器名解析為ip地址。

在"C:\WINDOWS\system32\drivers\etc\hosts"檔案中增加一條記錄:

   xxx.xxx.xxx.xxx 伺服器名


8、遠端伺服器上的名稱解析
  分散式事務的參與伺服器是需要相互訪問的,發起查詢的伺服器要根據機

器名或ip查詢遠端伺服器的,同樣遠端伺服器也要查詢發起伺服器,遠端伺服器通過發起伺服器的機器名查詢伺服器,所以要保證遠端伺服器能夠通過發起伺服器的機器名訪問到發起伺服器。一般的,兩個伺服器在同一網段機器名能就行很好的解析,但是也不保證都能很好的解析,所以比較保險的做法是:
在遠端伺服器的在"C:\WINDOWS\system32\drivers\etc\hosts"檔案中增加一條記錄:
     xxx.xxx.xxx.xxx 發起伺服器名

通過以上的一些列操作應該差不多了,這期間的操作你會抓狂,時而崩潰,時而暴走,筆者唯一的建議就是:將試驗、探索堅持到底,因為筆者已經證實SQLSERVER通過連結伺服器到oracle能夠使用分散式事務。

 1  -- 分散式事務測試
 2  set xact_abort ON
 3  begin tran
 4  insert into openquery(OraclePolice,'SELECT * FROM ALINK_SERVER_TEST ') values('456000','TESTtest','');
 5 
 6  if @@ERROR <>0
 7  rollback tran;
 8  else
 9  commit TRAN;
10  -- 語句執行成功