
簡(jiǎn)介ODAC122010Xcopy-x64.zip 是面向 .NET 開發(fā)者的 64 位 Oracle 數(shù)據(jù)訪問組件合集適合在 ASP.NET、服務(wù)端程序及 OLE DB 場(chǎng)景中連接 Oracle 12.2 數(shù)據(jù)庫覆蓋 ODP.NET、ASP.NET Providers 與事務(wù)服務(wù)等集成需求。壓縮包共 179 個(gè)文件、約 73.48MB包含 67 個(gè) dll 運(yùn)行時(shí)組件以及 sql、plb、ora 腳本config、exe、bat 安裝配置文件和 htm、txt 說明文檔。已有 1545 人學(xué)習(xí)下載對(duì)仍維護(hù) .NET Framework 4/2.0 項(xiàng)目的讀者較有參考價(jià)值。借助其中的 Instant Client 與各 Provider可快速核對(duì) 64 位部署文件排查程序集加載、連接配置和分布式事務(wù)協(xié)調(diào)問題降低版本收集與匹配成本。1. 內(nèi)網(wǎng)服務(wù)器不許裝數(shù)據(jù)庫客戶端這套 xcopy 包就是那條備用路徑給一臺(tái)不允許運(yùn)行安裝向?qū)У姆?wù)器補(bǔ)上數(shù)據(jù)訪問能力是 ASP.NET 老項(xiàng)目經(jīng)常撞上的場(chǎng)景站點(diǎn)跑在 .NET Framework 4 上要連 Oracle代碼里既有Oracle.DataAccess.Client也有幾段十年沒動(dòng)過的OraOLEDB.Oracle.1還有一處事務(wù)要用到 Oramts。正常做法是裝一個(gè)客戶端但機(jī)器策略不允許安裝程序一跑就被攔。ODAC122010Xcopy-x64.zip走的是另一條路解壓、復(fù)制、跑一個(gè)批處理把 odp.net4、oledb、oramts、asp.net 這幾組 DLL 鋪到指定目錄再按需寫注冊(cè)表和 machine.config。它解決的不是“性能更好”而是“這臺(tái)機(jī)器上根本沒有安裝程序可用”。適合手上維護(hù)著 .NET Framework 老站、又不能動(dòng)系統(tǒng)安裝包的從業(yè)者如果你的項(xiàng)目是 .NET Core / .NET 6直接引 NuGet 上的托管驅(qū)動(dòng)就行這套東西反而多余。2. 拆包先認(rèn)人五個(gè)子目錄與 odp.net4、oledb、oramts 的對(duì)應(yīng)關(guān)系壓縮包解開之后不要急著跑批處理先花五分鐘把目錄和 DLL 對(duì)上一遍。這個(gè)包里同時(shí)躺著好幾代驅(qū)動(dòng)名字相近、版本號(hào)相近認(rèn)錯(cuò)了就是后面幾小時(shí)的排查。先把對(duì)應(yīng)關(guān)系列清楚再?zèng)Q定裝哪幾組。2.1 目錄結(jié)構(gòu)與各組件的歸屬解壓后的頂層一般能看到odp.net、asp.net、oledb、oramts幾個(gè)目錄外加install.bat、configure.bat和一份 readme。下面這張表是我自己核對(duì)時(shí)用的映射實(shí)際文件名以包內(nèi)為準(zhǔn)但歸屬關(guān)系不會(huì)變目錄關(guān)鍵文件對(duì)應(yīng)技術(shù)棧部署時(shí)要?jiǎng)邮裁磑dp.net\bin\4Oracle.DataAccess.dll、oci.dll、oraociicus*.dllODP.NET 非托管驅(qū)動(dòng)程序集版本 4.122.1.0進(jìn) GAC 寫HKLM\SOFTWARE\Oracle\ODP.NET\4.122.1.0odp.net\bin\2.x同名的 2.x 版本老 .NET Framework 2.0/3.5 項(xiàng)目同上注冊(cè)表鍵為 2.122.1.0odp.net\managedOracle.ManagedDataAccess.dll純托管驅(qū)動(dòng)不依賴 oci.dll復(fù)制即可通常隨站點(diǎn) bin 目錄走asp.net\binOracle.Web.dllASP.NET 成員資格、角色、會(huì)話狀態(tài)提供程序復(fù)制 改 machine.configoledb\binOraOLEDB*.dllOLE DB 提供程序OraOLEDB.Oracle.1COM 注冊(cè) 寫 Provider 注冊(cè)表項(xiàng)oramts\binoraMTS.dll、Oracle.Services.For.MTS相關(guān)文件分布式事務(wù)資源管理器COM 注冊(cè) 配合 MSDTC表格里最容易被忽略的是oci.dll這一列。odp.net4 和 oledb 兩組都各自帶了一份 oci 相關(guān)的動(dòng)態(tài)庫它們不是擺設(shè)——非托管驅(qū)動(dòng)最終要靠它跟數(shù)據(jù)庫通信。所以部署時(shí)這兩組目錄不能只挑 DLL 拷得整目錄帶過去。2.2 odp.net4 和 2.x 的分界別按“新”來選按框架版本來選很多人一看有 4就覺得統(tǒng)統(tǒng)上 4。實(shí)際判斷標(biāo)準(zhǔn)只有一個(gè)引用方的程序集版本。.NET Framework 4.0 及以上編譯出來的項(xiàng)目引用的是Oracle.DataAccess, Version4.122.1.02.0/3.5 時(shí)代編譯的老程序集引用的是2.122.1.0。這兩個(gè)版本號(hào)是硬綁定CLR 加載時(shí)對(duì)不上就是FileLoadException或者一個(gè)更含糊的“無法加載文件或程序集”。所以一個(gè)站點(diǎn)里如果同時(shí)有 Framework 4 的主站和一個(gè)老的 2.0 工具庫兩組都得鋪不能只裝一組。托管驅(qū)動(dòng)Oracle.ManagedDataAccess是另一套邏輯它不注冊(cè) GAC、不寫 ODP.NET 注冊(cè)表鍵直接放進(jìn)站點(diǎn)的bin目錄就能用程序集版本是 4.122.1.0 那一條線。缺點(diǎn)是它和Oracle.DataAccess的類型不能混用命名空間雖然像但是兩個(gè)不同的程序集OracleConnection不是同一個(gè)類型。老代碼里寫死的Oracle.DataAccess.Client改造成本是有的這也就是為什么很多人最后還是回到非托管這條路。2.3 oledb 為什么還在不是所有老代碼都改得動(dòng)OraOLEDB.Oracle.1在這個(gè)包里占的比重不小原因很現(xiàn)實(shí)一堆十幾年前的 ASP 頁面、VBScript 腳本、Excel 宏、SSIS 包連接串里寫的就是ProviderOraOLEDB.Oracle.1。這些代碼沒人敢動(dòng)也找不到原始負(fù)責(zé)人重寫成 ODP.NET 的成本遠(yuǎn)高于把驅(qū)動(dòng)補(bǔ)上。OLE DB 提供程序是 COM 組件跟 .NET 程序集的部署方式完全不同。它要靠regsvr32注冊(cè)到注冊(cè)表的 CLSID 下還要在HKLM\SOFTWARE\Classes\OraOLEDB.Oracle里寫 Provider 的友好名和 CLSID 映射。install.bat 會(huì)替你干這件事手工部署時(shí)這一步最容易漏漏了之后的報(bào)錯(cuò)是“未在本地計(jì)算機(jī)上注冊(cè) OraOLEDB.Oracle.1 提供程序”看著像驅(qū)動(dòng)沒裝其實(shí)是 COM 沒登記。2.4 oramts只在真的需要分布式事務(wù)時(shí)才裝oramts 對(duì)應(yīng)的是 Oracle Services for MTS作用是讓 Oracle 連接能作為資源管理器參與 MSDTC 協(xié)調(diào)的分布式事務(wù)。典型場(chǎng)景是一個(gè)方法里同時(shí)操作 Oracle 和 SQL Server并且要求兩邊一起提交或回滾。這一組文件不裝普通事務(wù)照跑不誤只有TransactionScope里跨庫操作才會(huì)出問題。所以部署策略上我一般把它單獨(dú)拎出來先確認(rèn)業(yè)務(wù)里真有跨庫事務(wù)再裝。裝了之后還要確認(rèn) MSDTC 的配置否則一樣報(bào)錯(cuò)——這個(gè)在后面第 5 章會(huì)展開。3. 免安裝部署實(shí)操install.bat 與手工搬遷兩條路認(rèn)完目錄就可以動(dòng)手了。有兩條路一是讓包里的install.bat一把梭二是自己控制每一步拷貝和注冊(cè)。前者快適合有管理員權(quán)限、目標(biāo)目錄可以隨便定的機(jī)器后者慢但每一處改動(dòng)都清楚出問題時(shí)知道從哪退回去。3.1 用 install.bat 一次鋪開以管理員身份打開命令提示符進(jìn)解壓目錄執(zhí)行下面這條:: 切到解壓后的根目錄按實(shí)際路徑改 cd /d D:\pkg\ODAC122010Xcopy-x64 :: 第一個(gè)參數(shù)是組件all 表示全部第二個(gè)參數(shù)是目標(biāo)目錄 install.bat all C:\oracle\odac12c :: 如果上一步只做了文件復(fù)制再單獨(dú)執(zhí)行配置 configure.bat allinstall.bat的第一個(gè)參數(shù)接受組件名常見取值是all、odp.net4、odp.net2、asp.net、oledb、oramts第二個(gè)參數(shù)是目標(biāo)根目錄路徑里別帶空格和中文能省掉一堆麻煩。它的動(dòng)作是把對(duì)應(yīng)目錄的文件復(fù)制過去進(jìn) GAC 的注冊(cè)程序集寫 ODP.NET 的DllPath鍵注冊(cè) OLE DB 的 COM 組件并在 machine.config 里插入 ASP.NET 提供程序的配置節(jié)。configure.bat是“只做配置、不拷文件”的那一半?yún)?shù)同樣支持all和組件名后面可以再跟一個(gè) machine.config 的路徑來指定要改哪個(gè)文件。我習(xí)慣把它單獨(dú)跑一次原因很簡(jiǎn)單批處理里任何一步失敗整體退出碼不一定是非零分開跑能看出是哪一段沒成功。目標(biāo)目錄建議統(tǒng)一成C:\oracle\odac12c這種結(jié)構(gòu)不要塞進(jìn)Program Files。一是路徑里的空格在部分老腳本里會(huì)出問題二是后面要寫進(jìn)注冊(cè)表和 PATH 的路徑越短越好排查時(shí)肉眼比對(duì)也方便。提示install.bat 修改 machine.config 之前會(huì)備份原文件擴(kuò)展名通常帶.bak或時(shí)間戳。部署完成后先確認(rèn)備份存在再繼續(xù)后面的步驟。3.2 不讓動(dòng)系統(tǒng)目錄時(shí)的手工部署有些機(jī)器連C:\oracle都不讓寫只能放到應(yīng)用自己的目錄下比如D:\app\odac。這時(shí)候 install.bat 的全自動(dòng)流程會(huì)失敗一半得手工來。核心是四件事拷文件、注冊(cè)程序集、寫注冊(cè)表、加環(huán)境變量。先拷文件按組件分組拷別整包亂鋪:: 非托管 ODP.NET 4連同目錄里的 oci 相關(guān) DLL 一起 xcopy /E /I /Y D:\pkg\ODAC122010Xcopy-x64\odp.net\bin\4 D:\app\odac\odp\4 :: OLE DB 提供程序 xcopy /E /I /Y D:\pkg\ODAC122010Xcopy-x64\oledb\bin D:\app\odac\oledb :: ASP.NET 提供程序 xcopy /E /I /Y D:\pkg\ODAC122010Xcopy-x64\asp.net\bin D:\app\odac\aspnet/E連空目錄一起拷/I讓目標(biāo)被當(dāng)成目錄而不是文件/Y覆蓋時(shí)不問。這三件事在一臺(tái)要反復(fù)重裝的測(cè)試機(jī)上能省很多次回車。然后是注冊(cè)表和程序集。程序集進(jìn) GAC 需要gacutil一般隨 SDK 或 VS 的命令行環(huán)境提供:: 把非托管驅(qū)動(dòng)注冊(cè)進(jìn) GAC gacutil /i D:\app\odac\odp\4\Oracle.DataAccess.dll :: 寫 ODP.NET 的 DllPath讓運(yùn)行庫能找到同目錄的 oci reg add HKLM\SOFTWARE\Oracle\ODP.NET\4.122.1.0 /v DllPath /t REG_SZ /d D:\app\odac\odp\4 /freg add里的鍵名4.122.1.0必須和程序集版本嚴(yán)格對(duì)應(yīng)寫錯(cuò)一個(gè)數(shù)字驅(qū)動(dòng)就找不到自己的依賴報(bào)錯(cuò)是運(yùn)行時(shí)的DllNotFoundException而不是安裝期的提示。/f表示已存在就覆蓋重裝時(shí)要用。64 位系統(tǒng)上還有個(gè)坑32 位進(jìn)程讀的是HKLM\SOFTWARE\WOW6432Node\Oracle\...這條路徑。用 64 位包部署、卻讓 32 位應(yīng)用程序池去跑注冊(cè)表就寫到了另一棵樹上兩邊對(duì)不上。判斷方法見 3.3。最后是 TNS 相關(guān)。TNS_ADMIN指向放著tnsnames.ora、sqlnet.ora的目錄:: /M 表示寫系統(tǒng)級(jí)環(huán)境變量需要管理員權(quán)限 setx /M TNS_ADMIN D:\app\odac\network\adminsetx /M只影響之后新起的進(jìn)程已經(jīng)開著的 IIS 應(yīng)用池不會(huì)感知到改完必須回收應(yīng)用池或者iisreset。這一點(diǎn)在排查“命令行能連、站點(diǎn)連不上”時(shí)特別關(guān)鍵。3.3 驗(yàn)證部署四個(gè)檢查點(diǎn)按順序過裝完別急著讓業(yè)務(wù)去試自己先把四個(gè)點(diǎn)過一遍出問題能立刻定位到層。第一個(gè)點(diǎn)GAC 里有沒有這個(gè)程序集:: 列出 GAC 中所有 Oracle.DataAccess看版本號(hào) gacutil /l Oracle.DataAccess輸出里要能看到4.122.1.0那一條并且路徑指向你剛指定的目錄。如果只有舊版本說明前面gacutil /i沒成功或者被同名舊程序集擋住了。第二個(gè)點(diǎn)運(yùn)行庫能不能按版本號(hào)加載到它# 按完整程序集名加載成功會(huì)打印程序集全名和位置 [System.Reflection.Assembly]::Load(Oracle.DataAccess, Version4.122.1.0, Cultureneutral, PublicKeyToken89b483f429c47342) | Select-Object FullName, Location這條命令在 PowerShell 里跑注意位數(shù)要跟你的目標(biāo)進(jìn)程一致64 位進(jìn)程用 64 位 PowerShell32 位進(jìn)程用SysWOW64下的那個(gè)。加載成功但Location指向一個(gè)你沒預(yù)期的目錄那就是 GAC 里存在同版本的另一份屬于后面第 5 章要處理的情況。第三個(gè)點(diǎn)注冊(cè)表鍵的DllPath對(duì)不對(duì)reg query HKLM\SOFTWARE\Oracle\ODP.NET\4.122.1.0 /v DllPath值應(yīng)該等于 3.2 里寫進(jìn)去的目錄。如果這里指向了舊的客戶端安裝目錄運(yùn)行時(shí)會(huì)去那兒找 oci然后加載到不匹配的版本。第四個(gè)點(diǎn)最小連接測(cè)試。寫一個(gè)十行的控制臺(tái)程序或者直接用 PowerShell 加載驅(qū)動(dòng)連一次連接串里顯式帶上Data Source先別用 EZConnect 之外的別名排除 tnsnames 的干擾。四個(gè)點(diǎn)都過再讓站點(diǎn)去引。4. ASP.NET 站點(diǎn)接入machine.config、web.config 與 Oracle.Web 的配置順序驅(qū)動(dòng)鋪好了接下來是讓站點(diǎn)用上。這一步的順序很重要先改 machine.config 注冊(cè)提供程序再改 web.config 引用最后調(diào)權(quán)限。反過來做中間任何一步出錯(cuò)都會(huì)得到一個(gè)看不出根因的異常。4.1 Oracle.Web 在 machine.config 里的位置Oracle.Web.dll提供的是 Membership、Role、Profile、SessionState 這幾類 Provider它們要被 ASP.NET 的 Provider 模型識(shí)別必須在 machine.config 的system.web節(jié)里登記。configure.bat 的asp.net選項(xiàng)做的就是這件事它會(huì)往membership、roleManager、profile、sessionState里各插一段。如果機(jī)器上跑著多個(gè)站點(diǎn)、只有一個(gè)要用 Oracle 的提供程序我傾向于不動(dòng) machine.config改在站點(diǎn)自己的 web.config 里寫完整定義。原因很實(shí)際machine.config 是全局的改壞了所有站點(diǎn)一起掛而且回滾要靠備份文件手工還原。web.config 出問題最多影響一個(gè)應(yīng)用刪掉重啟就好。4.2 web.config 的連接串與 Provider 定義下面這段是一個(gè)最小可用的配置把連接串和成員資格提供程序都寫在站點(diǎn)級(jí)configuration connectionStrings !-- providerName 必須和實(shí)際使用的驅(qū)動(dòng)對(duì)上非托管寫 Oracle.DataAccess.Client -- add nameOraAspNetConString connectionStringUser Idapp;Password***;Data SourceORCLPDB;Poolingtrue;Min Pool Size1; providerNameOracle.DataAccess.Client / /connectionStrings system.web membership defaultProviderOracleMembershipProvider userIsOnlineTimeWindow15 providers add nameOracleMembershipProvider typeOracle.Web.Security.OracleMembershipProvider, Oracle.Web, Version4.122.1.0, Cultureneutral, PublicKeyToken89b483f429c47342 connectionStringNameOraAspNetConString applicationName/ enablePasswordRetrievalfalse enablePasswordResettrue requiresQuestionAndAnswerfalse requiresUniqueEmailfalse passwordFormatHashed maxInvalidPasswordAttempts5 minRequiredPasswordLength8 / /providers /membership /system.web /configurationtype屬性里的四段式程序集名不能省程序集名、版本、區(qū)域、公鑰標(biāo)記少一段就會(huì)走到“按簡(jiǎn)單名加載”的寬松匹配上可能加載到別的版本。connectionStringName要和上面connectionStrings里的name完全一致大小寫敏感。applicationName決定數(shù)據(jù)行的歸屬多個(gè)站點(diǎn)共用一個(gè)庫時(shí)這一項(xiàng)寫錯(cuò)會(huì)導(dǎo)致用戶互相看不見排查起來非常費(fèi)勁。passwordFormat選Hashed之后enablePasswordRetrieval必須是false兩個(gè)參數(shù)是聯(lián)動(dòng)的配錯(cuò)會(huì)在站點(diǎn)啟動(dòng)時(shí)直接拋配置異常。4.3 應(yīng)用程序池標(biāo)識(shí)與目錄權(quán)限驅(qū)動(dòng)文件和配置文件都就位了還有一個(gè)經(jīng)常被忘的環(huán)節(jié)應(yīng)用程序池用哪個(gè)身份跑那個(gè)身份就得能讀到部署目錄和注冊(cè)表鍵。默認(rèn)的ApplicationPoolIdentity是一個(gè)虛擬賬戶對(duì)D:\app\odac這種自建目錄通常沒有讀權(quán)限。表現(xiàn)是站點(diǎn)啟動(dòng)時(shí)報(bào)“拒絕訪問”或者提供程序初始化失敗異常堆棧指向配置文件加載看著像配置錯(cuò)其實(shí)是權(quán)限問題。給權(quán)限的方式是給對(duì)應(yīng)的虛擬賬戶授權(quán)而不是給Everyone:: 給應(yīng)用程序池虛擬賬戶讀執(zhí)行權(quán)限池名按實(shí)際改 icacls D:\app\odac /grant IIS APPPOOL\YourAppPool:(OI)(CI)RX /T(OI)(CI)表示繼承到子文件和子目錄RX是讀加執(zhí)行。加完回收應(yīng)用池再試。這一步在測(cè)試機(jī)上經(jīng)常被跳過因?yàn)闇y(cè)試時(shí)用的是管理員身份跑的控制臺(tái)程序權(quán)限天然是夠的一上 IIS 就翻車。4.4 兩條通路的代碼驗(yàn)證配置改完用一小段代碼把 ODP.NET 和 Oracle.Web 各驗(yàn)一遍using System; using Oracle.DataAccess.Client; // 非托管驅(qū)動(dòng)命名空間 using Oracle.Web.Security; // Oracle.Web 提供程序 class Probe { static void Main() { // 通路一直接用 ODP.NET 打開連接確認(rèn)驅(qū)動(dòng)與 oci 都正常 string cs User Idapp;Password***;Data SourceORCLPDB;Poolingtrue;; using (var conn new OracleConnection(cs)) { conn.Open(); using (var cmd new OracleCommand(select 1 from dual, conn)) { Console.WriteLine(ODP.NET OK: cmd.ExecuteScalar()); } } // 通路二通過 Oracle.Web 的提供程序創(chuàng)建用戶確認(rèn) Provider 配置生效 var provider Membership.Provider as OracleMembershipProvider; if (provider null) throw new InvalidOperationException(默認(rèn)成員資格提供程序不是 Oracle 實(shí)現(xiàn)); MembershipCreateStatus status; provider.CreateUser(probe_user, Pssw0rd!, probeexample.com, null, null, true, null, out status); Console.WriteLine(Oracle.Web status: status); } }第一段驗(yàn)證的是驅(qū)動(dòng)層能連上、能執(zhí)行說明Oracle.DataAccess.dll、oci 依賴、TNS_ADMIN三者都對(duì)。第二段驗(yàn)證的是配置層Membership.Provider拿到的類型不對(duì)說明 web.config 里的type或defaultProvider有問題拿到了但CreateUser拋異常通常是表結(jié)構(gòu)沒初始化或者連接串指向的庫不對(duì)。這里用as轉(zhuǎn)換而不是強(qiáng)轉(zhuǎn)是為了在類型不匹配時(shí)給出一個(gè)能看懂的異常而不是一個(gè)籠統(tǒng)的InvalidCastException。做部署驗(yàn)證時(shí)錯(cuò)誤信息本身就是排查的一半。5. 避坑與排查五類翻車現(xiàn)場(chǎng)的現(xiàn)象、成因與處置部署這套包踩過的坑八成集中在下面五類。每一條我都按“看到什么、為什么、怎么辦”寫方便對(duì)著報(bào)錯(cuò)直接查。5.1 BadImageFormatException位數(shù)不匹配現(xiàn)象站點(diǎn)一訪問就拋BadImageFormatException提示“試圖加載格式不正確的程序”堆棧停在加載Oracle.DataAccess那一行。原因應(yīng)用程序池開啟了 32 位兼容Enable 32-Bit Applications True進(jìn)程是 32 位的但裝的是 x64 的 xcopy 包GAC 里只有 64 位程序集。反過來也成立64 位進(jìn)程加載了 32 位驅(qū)動(dòng)。解決先確認(rèn)應(yīng)用池的位數(shù)設(shè)置再?zèng)Q定裝哪個(gè)包。要么把應(yīng)用池改成 64 位并確認(rèn)沒有其他 32 位依賴要么另外找 32 位包鋪一份。兩個(gè)都裝也行但注冊(cè)表得分開寫32 位進(jìn)程讀WOW6432Node那棵樹GAC 視角也不同這一點(diǎn)在 3.2 里提過。5.2 加載到舊版本GAC 里躺著同名程序集現(xiàn)象代碼明明按 4.122.1.0 編譯運(yùn)行時(shí)卻報(bào)方法不存在或者行為異常用Assembly.Load打印Location發(fā)現(xiàn)指向了一個(gè)舊的客戶端安裝目錄。原因機(jī)器上原本裝過數(shù)據(jù)庫客戶端或者更早的 ODACGAC 里有同名的Oracle.DataAccess。GAC 的查找規(guī)則優(yōu)先匹配版本但如果 web.config 里配了bindingRedirect或者引用的版本被合并過就會(huì)加載到舊的那份。更隱蔽的是DllPath指向舊目錄oci 版本和新驅(qū)動(dòng)不匹配表現(xiàn)為連接時(shí)崩潰而不是加載時(shí)崩潰。解決gacutil /l Oracle.DataAccess列出全部副本逐個(gè)比對(duì)版本和路徑確認(rèn)后卸載不用的版本或者在 web.config 里顯式寫bindingRedirect把舊版本重定向到新版本。DllPath鍵也要一起核對(duì)別只改一半。5.3 ORA-12154 / ORA-12541找不到連接描述符現(xiàn)象命令行用 sqlplus 能連站點(diǎn)連不上報(bào)ORA-12154: TNS: 無法解析指定的連接標(biāo)識(shí)符或者報(bào)ORA-12541: TNS: 無監(jiān)聽程序。原因前者的九成是TNS_ADMIN沒生效——改了系統(tǒng)變量但應(yīng)用池沒回收進(jìn)程里還是舊值或者tnsnames.ora放在了驅(qū)動(dòng)自帶的network\admin下而實(shí)際生效的是另一個(gè)目錄。后者多半是連接串里的主機(jī)端口寫錯(cuò)或者服務(wù)端監(jiān)聽確實(shí)沒起。解決先在應(yīng)用池的身份下確認(rèn)環(huán)境變量別用你自己的登錄會(huì)話去看。臨時(shí)驗(yàn)證可以在 web.config 的連接串里直接用 EZConnect 寫法host:port/service_name繞開 tnsnames能連就說明是解析問題而不是網(wǎng)絡(luò)問題。定位清楚再?zèng)Q定是修TNS_ADMIN還是修別名文件。5.4 OraOLEDB.Oracle.1 未注冊(cè)COM 沒登記現(xiàn)象老的 ASP 頁面或者 SSIS 包報(bào)“未在本地計(jì)算機(jī)上注冊(cè) OraOLEDB.Oracle.1 提供程序”。原因文件拷過去了但 COM 組件沒注冊(cè)或者注冊(cè)了但位數(shù)不對(duì)32 位進(jìn)程找不到 64 位的注冊(cè)項(xiàng)。解決用管理員權(quán)限對(duì)OraOLEDB*.dll執(zhí)行regsvr3232 位組件要用SysWOW64\regsvr32.exe。注冊(cè)完在注冊(cè)表里確認(rèn)HKLM\SOFTWARE\Classes\OraOLEDB.Oracle下的 CLSID 指向正確路徑。注意 OLEDB 提供程序依賴 oci整目錄拷貝別只挑一個(gè) DLL。5.5 Oramts 裝了還是事務(wù)失敗MSDTC 沒配現(xiàn)象TransactionScope里同時(shí)操作兩個(gè)庫提交時(shí)報(bào)分布式事務(wù)相關(guān)的錯(cuò)誤或者干脆超時(shí)。原因oramts 只是讓 Oracle 連接能參與分布式事務(wù)真正的協(xié)調(diào)者是 MSDTC。MSDTC 未開啟網(wǎng)絡(luò) DTC 訪問、未允許入站/出站、防火墻擋了 RPC 端口都會(huì)讓事務(wù)在提升階段失敗。另外連接串里如果沒開enlist連接根本不會(huì)自動(dòng)登記到事務(wù)里。解決先確認(rèn)連接串行為再檢查 MSDTC 的安全配置網(wǎng)絡(luò) DTC 訪問、事務(wù)管理器通信、入站出站授權(quán)最后看防火墻。這一條排查鏈路長(zhǎng)我一般從“能不能只用本地事務(wù)”倒推如果業(yè)務(wù)允許把跨庫操作拆開能省掉整條鏈路的不確定性。6. 版本共存與回滾把這次部署做成可撤銷的一步部署這套東西最容易留下的隱患不是裝不上而是裝完之后沒法干凈地退回去。GAC 里的程序集、注冊(cè)表鍵、machine.config 的改動(dòng)、COM 注冊(cè)四樣?xùn)|西分散在四個(gè)地方出問題時(shí)想還原得靠記憶。我現(xiàn)在做這類部署會(huì)強(qiáng)制留一份可撤銷的清單。先做備份四樣?xùn)|西各存一份對(duì)象備份方式還原命令GAC 程序集記錄gacutil /l的輸出存成文本gacutil /u Oracle.DataAccess,Version4.122.1.0,...ODP.NET 注冊(cè)表鍵reg export導(dǎo)出整個(gè)Oracle\ODP.NET子樹reg import odac_backup.regmachine.config復(fù)制一份帶日期的副本直接覆蓋回原路徑OLE DB COM 注冊(cè)記錄 CLSID 和 DLL 路徑regsvr32 /u反注冊(cè)導(dǎo)出注冊(cè)表這一步用一行命令就夠:: 部署前導(dǎo)出出問題一條命令還原 reg export HKLM\SOFTWARE\Oracle\ODP.NET D:\backup\odpnet_before.reg /y reg export HKLM\SOFTWARE\Classes\OraOLEDB.Oracle D:\backup\oledb_before.reg /y/y覆蓋同名文件路徑提前建好。等真出事的時(shí)候你不會(huì)有心情去找“備份到底存哪了”。版本共存的處理上我的做法是同一臺(tái)機(jī)器只保留一條主線。要么全用非托管Oracle.DataAccess4.122.1.0要么全用托管Oracle.ManagedDataAccess不要在一個(gè)應(yīng)用里混?;煊玫闹苯雍蠊穷愋筒患嫒軴racleConnection來自兩個(gè)不同程序集編譯期不報(bào)錯(cuò)、運(yùn)行期轉(zhuǎn)換失敗。如果確實(shí)有老代碼改不動(dòng)就讓它單獨(dú)跑在一個(gè)應(yīng)用池里用舊版本跟新站物理隔開。還有一個(gè)驗(yàn)證習(xí)慣值得養(yǎng)成部署完成后在測(cè)試機(jī)上跑一次“斷開再連”的完整流程而不是只用一條select 1 from dual驗(yàn)證。具體做法是把應(yīng)用池停掉、清空連接池、再啟動(dòng)然后走一遍登錄和一次跨庫事務(wù)。連接池里殘留的舊連接會(huì)掩蓋掉很多問題只有重啟之后第一次建連才暴露真實(shí)的配置狀態(tài)。最后說個(gè)我自己的教訓(xùn)。早些年做這類 xcopy 部署我圖省事直接在機(jī)器上跑install.bat all跑完就交付了。兩個(gè)月后那臺(tái)機(jī)器要升級(jí)運(yùn)維問我“當(dāng)初改了哪些地方”我翻不出任何記錄只能對(duì)著注冊(cè)表和 machine.config 一點(diǎn)點(diǎn)比對(duì)花了整整一個(gè)下午。從那以后我每次做 xcopy 部署都強(qiáng)制走一遍“先導(dǎo)出注冊(cè)表、再跑批處理、最后記一份變更清單”的流程清單里連目標(biāo)目錄和DllPath的值都寫清楚。慢十分鐘省一下午。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取