
簡介面向 .NET 平臺連接 Oracle 數(shù)據(jù)庫的 64 位組件合集覆蓋 ODP.NET 4 與 2.0、ASP.NET Providers、OLE DB、Microsoft Transaction Server 服務(wù)及 Instant Client版本為 12.2.0.1.0。適合需要在 ASP.NET、WinForm 或服務(wù)端程序中接入 Oracle 的開發(fā)人員與運(yùn)維人員用于免安裝或 xcopy 方式快速部署數(shù)據(jù)訪問組件減少環(huán)境配置與版本匹配上的反復(fù)排查。壓縮包共 179 個文件約 73.48MB以 67 個 dll 為主另含 38 個 sql、17 個 plb、14 個 sym、10 個 config、10 個 exe 和 9 個 bat 等分別對應(yīng)程序集、數(shù)據(jù)庫腳本、符號與配置、安裝卸載及注冊批處理等用途。已有 1545 人學(xué)習(xí)說明其在 Oracle 客戶端與 .NET 互操作場景中具有一定參考價值。目錄中的批處理與配置項(xiàng)可輔助完成注冊、卸載和環(huán)境校驗(yàn)配合 SQL 與示例配置便于讀者搭建可復(fù)用的連接環(huán)境并理解 ODP.NET 與 OLE DB 等組件的部署差異。1. 免安裝的 Oracle 數(shù)據(jù)訪問層ODAC 12.2 xcopy 包能解決什么服務(wù)器只給了你一個目錄的寫權(quán)限裝不了 Oracle 客戶端可 ASP.NET 站點(diǎn)第二天就要連庫——ODAC122010Xcopy-x64.zip 就是為這種場面準(zhǔn)備的。它把 ODAC 12.2 的 ODP.NET、OLE DB、ORAMTS 以純文件形式交付解壓落位、補(bǔ)齊路徑和配置進(jìn)程起來就能用全程不碰安裝器也不用去改 machine.config。適合 .NET Framework 4.x 的 Web 與桌面程序適合要把數(shù)據(jù)庫驅(qū)動固化進(jìn)部署包的流水線也適合機(jī)器上已經(jīng)躺著兩三個版本 Oracle 客戶端、再加一個就要打架的老環(huán)境。反過來指望圖形化配 TNS、指望 ORAMTS 分布式事務(wù)開箱即用、或者團(tuán)隊(duì)里沒人愿意讀 PATH 和注冊表的裝完整客戶端更省心。2. 包里有什么、該選哪個ODP.NET4、OLE DB 與 ORAMTS 的邊界拿到壓縮包先別急著解壓到站點(diǎn)目錄里。這個包里同時塞了四五套彼此獨(dú)立的數(shù)據(jù)訪問組件它們共享一部分原生庫但注冊方式、調(diào)用方式、依賴條件完全不同。選錯了組件后面所有排查都是在錯誤的地基上打補(bǔ)丁。先花十分鐘把目錄結(jié)構(gòu)過一遍比上線后盯著BadImageFormatException猜要劃算得多。2.1 四個組件不是一回事先認(rèn)清你要的是哪一個按目錄粗分xcopy 包通常包含這么幾塊odp.net下的托管與非托管 ODP.NET、oledb下的 Oracle Provider for OLE DB 與 ORAMTS 相關(guān)文件、asp.net下的 ASP.NET 提供程序、以及 ODBC 那一套。它們的定位差別很大組件主要文件調(diào)用方式是否依賴原生庫典型場景ODP.NET 非托管驅(qū)動Oracle.DataAccess.dllOracle.DataAccess.Client命名空間是依賴 OCI 系列原生庫老 .NET Framework 項(xiàng)目需要非托管驅(qū)動的高級特性O(shè)DP.NET 托管驅(qū)動Oracle.ManagedDataAccess.dllOracle.ManagedDataAccess.Client否純托管新項(xiàng)目、部署環(huán)境干凈、不想管 PATHOLE DB 提供程序OraOLEDB.dllOleDbConnection、SSIS、報(bào)表工具是且需要 COM 注冊只能走 OLE DB 的第三方工具鏈ORAMTSoramts 相關(guān)文件System.Transactions/ COM 隱式登記是且依賴恢復(fù)服務(wù)Oracle 與其它資源管理器混在一個分布式事務(wù)里選型的第一條判斷標(biāo)準(zhǔn)很簡單代碼里using的是哪個命名空間。寫著Oracle.DataAccess.Client的只有非托管驅(qū)動能接寫著Oracle.ManagedDataAccess.Client的托管驅(qū)動就夠了而且完全不用碰 PATH——這是最省事的一條路。只有當(dāng)項(xiàng)目里出現(xiàn)OleDbConnection加ProviderOraOLEDB.Oracle這種連接串才必須動 OLE DB 那一套。第二條判斷標(biāo)準(zhǔn)是事務(wù)模型。如果你的代碼里出現(xiàn)TransactionScope并且同一個事務(wù)里既寫了 Oracle 又寫了 SQL Server 或 MQ那就是分布式事務(wù)非托管驅(qū)動會嘗試通過 ORAMTS 登記成資源管理器。這一塊是 xcopy 部署最容易翻車的地方后面單獨(dú)說。2.2 xcopy 與安裝版的差別省掉的是什么代價是什么安裝版 ODAC 干了四件事往 GAC 里放程序集、往 machine.config 里寫DbProviderFactories節(jié)點(diǎn)、往注冊表里寫 OLE DB 的 COM 注冊信息、注冊 Windows 服務(wù)并把原生庫路徑塞進(jìn) PATH。xcopy 版一件都不干它只給你文件。省下來的是管理員權(quán)限和“裝完影響全機(jī)器”的心理負(fù)擔(dān)代價是這四件事得你自己在應(yīng)用層面補(bǔ)齊。好處也很實(shí)在應(yīng)用隔離。同一臺機(jī)器上兩個站點(diǎn)一個要 11.2 的非托管驅(qū)動一個要 12.2 的安裝版只能裝一個xcopy 版可以各帶各的目錄、各寫各的 web.config互不干擾。GAC 里沒有注冊也就意味著不會出現(xiàn)“升級客戶端把別人的老應(yīng)用搞掛”這種事故。代價集中在三處。第一GAC 里沒有程序集綁定完全靠bin目錄和配置里的版本號寫錯一個數(shù)字就是FileLoadException。第二machine.config 里沒有DbProviderFactories.GetFactory(Oracle.DataAccess.Client)直接拋“未找到指定提供程序”必須在應(yīng)用配置文件里補(bǔ)。第三ORAMTS 依賴的恢復(fù)服務(wù)是 Windows 服務(wù)xcopy 包里的文件只是組件服務(wù)本體需要單獨(dú)注冊拿不到就別指望分布式事務(wù)。版本上還有一條硬邊界這個 12.2 的包面向 .NET Framework 4.x程序集版本形如4.122.x.x。項(xiàng)目如果已經(jīng)遷到 .NET Core 或更高版本的 .NET包里這套托管驅(qū)動幫不上忙得換對應(yīng)的新版本組件。開工前先確認(rèn)web.config里的targetFramework別解壓完了才發(fā)現(xiàn)用不上。3. 部署實(shí)操把壓縮包解到站點(diǎn)目錄并讓進(jìn)程找得到部署這件事的難點(diǎn)不在“解壓”在“讓 w3wp.exe 在正確的時刻、從正確的目錄、加載正確的那份 DLL”。Windows 的 DLL 搜索順序、IIS 的應(yīng)用池回收時機(jī)、GAC 的優(yōu)先級三者疊加起來足夠讓人懷疑人生。下面這套順序是我自己反復(fù)用過的照著走能把大部分不確定性提前消掉。3.1 解壓與目錄布局路徑、位數(shù)、命名三件事路徑要短、要純英文、要固定。三個要求都不是潔癖路徑里有空格會讓某些命令行參數(shù)解析出問題路徑里有中文在部分編碼環(huán)境下會讀到亂碼文件名路徑不固定則意味著每次換機(jī)器都要改配置配置文件一進(jìn)版本庫就變成了環(huán)境耦合。# 解壓到短路徑、純英文目錄不要放 C:\Program Files 或帶中文的路徑 Expand-Archive -Path .\ODAC122010Xcopy-x64.zip -DestinationPath D:\odac\x64 -Force # 先看清目錄結(jié)構(gòu)再決定哪個文件夾進(jìn) PATH Get-ChildItem D:\odac\x64 -Directory -Recurse -Depth 2 | Select-Object -ExpandProperty FullName-DestinationPath一旦定下來就別再改后面配置里的路徑、PATH 里的條目、運(yùn)維文檔里的說明全都指向它。-Force用于覆蓋上一次部署的殘留文件避免新舊 DLL 混在一個目錄里——這種混裝排查起來極其難受因?yàn)槲募粯?、大小不同。解壓完立刻做位?shù)確認(rèn)。這個包是 x64 的原生組件只有 64 位版本如果站點(diǎn)跑在“啟用 32 位應(yīng)用程序”的應(yīng)用池里加載原生庫時必然失敗。確認(rèn)方式不是看操作系統(tǒng)而是看應(yīng)用池設(shè)置# 列出所有應(yīng)用池的 32 位開關(guān)True 的那些站點(diǎn)不能直接用 x64 原生組件 Import-Module WebAdministration Get-IISAppPool | Select-Object Name, {nEnable32Bit;e{ (Get-Item IIS:\AppPools\$($_.Name)).enable32BitAppOnWin64 }}這一步的產(chǎn)出應(yīng)該是一張清單哪些應(yīng)用池是 32 位的哪些是 64 位的。32 位的要么改成 64 位前提是它依賴的其它組件也支持要么這個包對它無效。別想著兩邊都兼容混合位數(shù)部署最后一定會亂。3.2 讓進(jìn)程找得到原生庫PATH、權(quán)限與進(jìn)程重啟托管程序集好辦拷到站點(diǎn)bin目錄就行CLR 會去那兒找。原生庫不好辦非托管 ODP.NET 和 OLE DB 在運(yùn)行時要LoadLibrary一批ora*.dll、oci.dll這些文件的搜索路徑跟著宿主進(jìn)程走而宿主是w3wp.exe不在你的站點(diǎn)目錄里。把原生 DLL 丟進(jìn)bin賭它被找到成功與否取決于宿主怎么發(fā)起加載不建議賭。常見做法是改機(jī)器級 PATH把組件目錄加進(jìn)去# 追加而不是覆蓋覆蓋 PATH 是能把整臺機(jī)器搞癱的操作 $old [Environment]::GetEnvironmentVariable(PATH,Machine) $new D:\odac\x64\odp.net\bin\4;D:\odac\x64\oledb\bin;$old [Environment]::SetEnvironmentVariable(PATH, $new, Machine) # 給應(yīng)用池身份讀執(zhí)行權(quán)限缺權(quán)限的表現(xiàn)是“找不到模塊”而不是“拒絕訪問” icacls D:\odac\x64 /grant IIS_IUSRS:(OI)(CI)(RX) /T改完 PATH 必須重啟 IIS因?yàn)閣3wp.exe只在啟動時繼承環(huán)境變量光回收應(yīng)用池不夠# 回收應(yīng)用池不會重新讀取機(jī)器環(huán)境變量必須重啟 W3SVC iisreset /restart(OI)(CI)(RX)是繼承到子目錄的讀加執(zhí)行權(quán)限夠用且最小化。注意 PATH 的追加順序把 ODAC 目錄放在$old前面是為了讓它優(yōu)先于機(jī)器上可能已存在的其它 Oracle 客戶端目錄被搜索到。這個順序在后面排查“加載了錯誤版本 DLL”時是關(guān)鍵線索別隨手改成追加到末尾。3.3 托管程序集落位與版本綁定托管 DLL 拷貝到站點(diǎn)bin這是唯一推薦的位置。不要往 GAC 里塞——gacutil本身就未必有而且塞進(jìn)去之后應(yīng)用之間的隔離性就沒了等于把 xcopy 的最大優(yōu)勢扔掉。# 托管程序集進(jìn)站點(diǎn) bin原生庫走 PATH兩條路徑分開管理 $bin D:\sites\demo\bin Copy-Item D:\odac\x64\odp.net\bin\4\Oracle.DataAccess.dll $bin -Force # 讀真實(shí)版本號和公鑰標(biāo)記配置里填的 version 必須和這里完全一致 $an [Reflection.AssemblyName]::GetAssemblyName($bin\Oracle.DataAccess.dll) [PSCustomObject]{ Name $an.Name Version $an.Version.ToString() Token ($an.GetPublicKeyToken() | ForEach-Object { $_.ToString(x2) }) -join }這段輸出的Version和Token是下一步寫配置的輸入不要憑記憶填。網(wǎng)上流傳的版本號五花八門抄錯了就是Could not load file or assembly ... Versionx.x.x.x。同一個程序集名在不同小版本之間版本號會變公鑰標(biāo)記通常穩(wěn)定但版本號必須實(shí)測。如果機(jī)器 GAC 里已經(jīng)存在同名程序集比如以前裝過完整客戶端CLR 可能優(yōu)先加載 GAC 里那份舊版本導(dǎo)致bin里的文件形同虛設(shè)。判斷方法在最后一章的驗(yàn)證環(huán)節(jié)里給。真要強(qiáng)制走本地文件就在配置文件里加bindingRedirect把舊版本重定向到你實(shí)際帶的版本。4. 配置實(shí)操DbProviderFactories 注冊與連接串參數(shù)文件到位只是讓程序“能加載”配置到位才讓它“能用”。這一章的三塊配置各管一件事DbProviderFactories管工廠方法能不能拿到提供程序connectionStrings管連接怎么建立和復(fù)用OLE DB 與 ORAMTS 的額外注冊管特定的調(diào)用路徑。三塊都補(bǔ)齊才算真正跑通。4.1 DbProviderFactories讓 GetFactory 認(rèn)得 ODP.NET安裝版會往 machine.config 寫節(jié)點(diǎn)xcopy 版不寫所以應(yīng)用配置文件里必須先remove再add。remove不能省——機(jī)器上如果存在安裝版留下的舊條目不 remove 會直接報(bào)重復(fù)鍵。configuration system.data DbProviderFactories !-- 先移除防止機(jī)器上安裝版留下的同名條目沖突 -- remove invariantOracle.DataAccess.Client / add nameODP.NET, Unmanaged Driver invariantOracle.DataAccess.Client descriptionOracle Data Provider for .NET, Unmanaged Driver typeOracle.DataAccess.Client.OracleClientFactory, Oracle.DataAccess, Version4.122.1.0, Cultureneutral, PublicKeyToken89b483f429c47342 / /DbProviderFactories /system.data /configuration四個屬性各有分工。invariant是代碼里傳的名字必須和GetFactory(...)的字符串一模一樣大小寫不敏感但拼寫必須對。type是三段式程序集限定名完整類型名、程序集名、版本加公鑰標(biāo)記缺一段都會加載失敗。name和description只影響可讀性但填清楚對后來接手的人友好。版本號那一段用 3.3 節(jié)實(shí)測出來的值替換。如果項(xiàng)目代碼直接new OracleConnection()而不用工廠這段配置可以不加但只要代碼里出現(xiàn)DbProviderFactories.GetFactory或者在用依賴工廠抽象的 ORM、報(bào)表組件就必須加。4.2 連接串描述符、TNS_ADMIN 與 EZConnect連接串的寫法決定了要不要依賴tnsnames.ora。xcopy 部署最怕的就是“機(jī)器上沒配 TNS”所以我的默認(rèn)選擇是直接把完整描述符寫進(jìn)連接串徹底繞開解析環(huán)節(jié)connectionStrings add nameora connectionStringUser Idapp_user;Password***;Data Source(DESCRIPTION(ADDRESS(PROTOCOLTCP)(HOST10.0.0.10)(PORT1521))(CONNECT_DATA(SERVICE_NAMEORCLPDB1)));Poolingtrue;Min Pool Size2;Max Pool Size80;Connection Timeout15;Statement Cache Size50;Self Tuningfalse; providerNameOracle.DataAccess.Client / /connectionStrings參數(shù)逐個說明。Data Source用描述符而不是別名省掉TNS_ADMIN和tnsnames.ora的全部麻煩代價是連接信息進(jìn)了配置文件需要走配置加密或環(huán)境變量注入。Poolingtrue是默認(rèn)值顯式寫出來是為了讓人看見。Min Pool Size2讓應(yīng)用啟動后立刻有可用連接避免首個請求承擔(dān)建連延遲Max Pool Size80要低于數(shù)據(jù)庫端的會話上限除以實(shí)例數(shù)拍腦袋填 200 是連接池打滿的常見起點(diǎn)。Connection Timeout15短于大多數(shù)網(wǎng)關(guān)的超時能讓故障快速暴露而不是把線程掛死。Statement Cache Size50緩存游標(biāo)對反復(fù)執(zhí)行同一批 SQL 的站點(diǎn)收益明顯。Self Tuningfalse只在連接數(shù)很多的場景下建議關(guān)掉默認(rèn)開著會周期性做負(fù)載探測。代碼側(cè)用工廠拿連接換驅(qū)動時只改配置不改代碼// 走工廠而不是 new換托管/非托管驅(qū)動時只動 web.config var factory DbProviderFactories.GetFactory(Oracle.DataAccess.Client); using (var conn factory.CreateConnection()) { conn.ConnectionString ConfigurationManager.ConnectionStrings[ora].ConnectionString; conn.Open(); using (var cmd conn.CreateCommand()) { // 用 dual 做最小連通性驗(yàn)證比 select 1 更貼近 Oracle 的實(shí)際語法 cmd.CommandText select sys_context(userenv,sid) from dual; var sid cmd.ExecuteScalar(); } }CreateConnection返回的是DbConnection基類后面所有操作都通過基類接口完成這樣遷移到托管驅(qū)動時業(yè)務(wù)代碼零改動。這段代碼同時也是最好的冒煙測試能拿到sid說明工廠注冊、程序集加載、連接串解析、網(wǎng)絡(luò)連通四件事全部通過。4.3 OLE DB 與 ORAMTS 的啟用條件OLE DB 是 COM 組件光有文件不夠必須注冊到系統(tǒng)里# COM 組件注冊/s 靜默失敗時去掉 /s 看錯誤彈窗 regsvr32 /s D:\odac\x64\oledb\bin\OraOLEDB.dll注冊成功只解決了一半。OLE DB 提供程序還需要一個 ProgID 到 CLSID 的映射鍵安裝版會自動寫xcopy 版通常要手工補(bǔ)。別從網(wǎng)上抄 GUID——regsvr32執(zhí)行后到注冊表里查這個 DLL 實(shí)際注冊出來的 CLSID用真實(shí)的那個建OraOLEDB.Oracle鍵。抄錯 GUID 的表現(xiàn)是“提供程序已注冊但仍然找不到”比沒注冊更難查。ORAMTS 的條件更嚴(yán)格。它需要在系統(tǒng)里有一個恢復(fù)服務(wù)來協(xié)調(diào)兩階段提交xcopy 包里的文件只是客戶端側(cè)組件。沒有這個服務(wù)TransactionScope提升為分布式事務(wù)時會在登記階段失敗。判斷自己是否真的需要它如果整個事務(wù)只碰一個 Oracle 庫那就是本地事務(wù)根本走不到 ORAMTS只有跨庫、跨資源管理器才需要。多數(shù)所謂“需要分布式事務(wù)”的場景拆開成補(bǔ)償邏輯反而更可靠。5. 避坑與排查五類上線后才會暴露的問題下面這五條都是本地跑得好好的、一上服務(wù)器就出問題的類型。共同點(diǎn)是錯誤信息指向的方向和真正的原因往往差得很遠(yuǎn)照著報(bào)錯原文去搜十有八九搜到的是另一個場景的答案。5.1 加載期的三類翻車現(xiàn)象應(yīng)用一啟動就拋“未能加載文件或程序集”或“試圖加載格式不正確的程序”。原因位數(shù)不匹配或者程序集版本號和配置里寫的不一致。前者發(fā)生在應(yīng)用池開了 32 位模式卻加載 x64 原生庫后者發(fā)生在配置文件里的Version和bin里實(shí)際文件的版本對不上。解決先用 3.2 節(jié)的命令確認(rèn)應(yīng)用池位數(shù)再用 3.3 節(jié)的腳本讀出真實(shí)版本號覆蓋配置。兩條都確認(rèn)過還報(bào)錯就去查 GAC 里是不是有同名舊版本搶先加載了?,F(xiàn)象代碼里明明用的是bin下的新 DLL運(yùn)行行為卻像舊版本某些新方法報(bào)MissingMethodException。原因GAC 里存在同名程序集CLR 的加載順序讓它優(yōu)先命中 GAC。xcopy 部署最常見的隱形對手就是這個。解決在配置里加bindingRedirect強(qiáng)制重定向到實(shí)際版本或者干脆在目標(biāo)機(jī)器上卸掉舊的安裝版客戶端。判斷當(dāng)前到底加載了哪份文件用最后一章的命令看進(jìn)程模塊列表。現(xiàn)象OLE DB 連接報(bào)“未在本地計(jì)算機(jī)上注冊‘OraOLEDB.Oracle’提供程序”。原因regsvr32沒執(zhí)行、執(zhí)行失敗往往是權(quán)限不夠或者注冊了但缺少 ProgID 映射鍵。解決以管理員身份重跑regsvr32成功后查注冊表確認(rèn) CLSID 真實(shí)存在再補(bǔ) ProgID 鍵。64 位進(jìn)程只認(rèn) 64 位注冊信息32 位工具能連通不代表站點(diǎn)能連通。5.2 連接與事務(wù)期的兩類翻車現(xiàn)象報(bào) ORA-12154“無法解析指定的連接標(biāo)識符”或者 ORA-01804 初始化 OCI 失敗。原因前者是連接串用了別名但沒有可解析的tnsnames.ora或者TNS_ADMIN指向了錯誤目錄后者是進(jìn)程加載到了別的路徑下的oci.dll版本和驅(qū)動不配套。解決優(yōu)先改成 4.2 節(jié)的完整描述符寫法繞開解析。如果必須用別名把TNS_ADMIN顯式設(shè)成組件目錄并把tnsnames.ora放進(jìn)去同時確認(rèn) PATH 里 ODAC 目錄排在其它客戶端目錄之前?,F(xiàn)象單庫操作正常一進(jìn)TransactionScope就報(bào)事務(wù)登記失敗或超時。原因事務(wù)被提升為分布式事務(wù)但 ORAMTS 的恢復(fù)服務(wù)不存在或沒啟動。解決先確認(rèn)是否真的跨了資源管理器只碰一個庫的話改用OracleTransaction顯式事務(wù)問題直接消失。確實(shí)需要跨庫就得把恢復(fù)服務(wù)補(bǔ)齊這時候 xcopy 的便利性讓位給安裝版更省事。6. 驗(yàn)證與調(diào)優(yōu)確認(rèn)加載的是哪一份 DLL配置全對、程序能跑仍然不能算部署完成——你得能證明進(jìn)程里掛的是你以為的那份文件。這件事在出故障時價值最大所有“版本不對”的懷疑都能用一條命令終結(jié)。# 看站點(diǎn)進(jìn)程實(shí)際加載了哪些 Oracle 相關(guān)模塊路徑比版本號更能說明問題 Get-Process w3wp -ErrorAction SilentlyContinue | ForEach-Object { $proc $_ $_.Modules | Where-Object { $_.ModuleName -match ^(Oracle|ora) } | Select-Object {nPid;e{$proc.Id}}, ModuleName, FileName } | Format-Table -AutoSizeFileName那一列就是你想要的全部答案。它如果指向D:\odac\x64\...說明 PATH 生效了如果指向某個老的客戶端 home說明搜索順序被別人搶了回頭調(diào) PATH 順序。ModuleName里出現(xiàn)oramts說明進(jìn)程確實(shí)在嘗試分布式事務(wù)路徑這和代碼里有沒有TransactionScope能互相印證。一個常見誤解是把“能連上庫”當(dāng)成部署成功的標(biāo)志。連接成功只覆蓋了托管層和網(wǎng)絡(luò)層原生庫的版本兼容問題往往要等到某條特定 SQL、某個 LOB 操作才暴露。所以我的習(xí)慣是連接驗(yàn)證之外再加一步模塊路徑核對兩件事都過才算收工。參數(shù)上還有兩個值值得按真實(shí)負(fù)載調(diào)Statement Cache Size在 SQL 重復(fù)率高的站點(diǎn)可以提到 100 以上但每個緩存游標(biāo)都占服務(wù)端資源盲目調(diào)大反而增加共享池壓力Max Pool Size直接決定數(shù)據(jù)庫端會話數(shù)的峰值先在測試環(huán)境壓一遍看實(shí)際并發(fā)再乘個 1.2 的系數(shù)比直接抄網(wǎng)上的數(shù)字靠譜得多。從那以后我每上一個新環(huán)境第一件事都是先跑一遍模塊路徑核對再談功能驗(yàn)證——省下來的不是排查時間是不用在下班前半小時懷疑人生的運(yùn)氣。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取