解決 ASP.NET 跑在 x64 機器上無法連接 Oracle DB 的問題

今天又解決一個十分棘手的問題,我們有個專案原本在 x86 機器上開發 ( 資料庫採用 Oracle ),最近由於主機升級到 Windows 7 (x64) 後發現程式出問題,當在 Visual Studio 中按下 F5 進行測試除錯時完全無法連接到資料庫,而且一整個很沒道理,看看我如何解決這個棘手的問題吧。

我遇到的錯誤如下:

ORA-12154: TNS: 無法解析指定的連線 ID
ORA-12154:TNS:could not resolve service name

錯誤發生點是在「建立連線」的程式碼,只要 Open Connection 就會立即出錯。

這問題首先是出在我同事的身上,他主機在一個多月前換成 Windows Server 2008 (x64),而我是最近才換到 Windows 7 (x64),問題跟他一模一樣,因此也花了好多時間研究分析,直到剛剛跟黑大討論一番後終於給我找出解法。

先說說我電腦的安裝步驟與執行環境:

  • 安裝 Oracle Database 10g Client Release 2 (10.2.0.1.0) for Microsoft Windows (32-bit)
  • 設定 TNSNAMES.ORA 設定檔 ( 100% 肯定設定沒問題 )
  • 使用 SQL Plus 可以正常連線
  • 使用 SQL Developer 可以正常連線
  • 在 Visual Studio 中可以建置(Build)專案,建置/編譯後的組件部署到測試機也都沒問題
  • 在 Visual Studio 中使用內建的 ASP.NET 開發伺服器進行測試
  • 利用 Process Explorer 查看 WebDev.WebServer.EXE 程式,載入的組件都沒問題 (正確載入)
  • 利用 Prcoess Monitor 查看 WebDev.WebServer.EXE 程式,載入的 Oracle Client 相關參數檔路徑也都正確無誤

想破頭無法解決時,黑大建議我用最簡單的方式測試資料庫連線 (如下範例),雖然我自己已經測試數十遍了,但我還是不鐵齒,聽話的再測一次 ( 魔鬼總在細節裡 ):

using (OracleConnection cn = new OracleConnection(
    "Data Source=MyName;" +
    "Persist Security Info=True;" + 
    "User ID=user;" +
    "Password=pass"))
{
    cn.Open(); // 在此發生【 ORA-12154: TNS: 無法解析指定的連線 ID 】的錯誤
}

這時我才想到將 TNSNAME 的完整定義移到這裡試試看,請看如下範例:

using (OracleConnection cn = new OracleConnection(
    "Data Source=" +
    "  (DESCRIPTION =" +
    "    (ADDRESS_LIST =" +
    "      (ADDRESS = (PROTOCOL = TCP)(HOST = 10.0.0.245)(PORT = 1521))" +
    "    )" +
    "    (CONNECT_DATA =" +
    "      (SERVICE_NAME = MyName)" +
    "    )" +
    "  )" +
    ";Persist Security Info=True;User ID=user;Password=pass"))
{
    cn.Open(); // 在此時發生【 ORA-6413: 連線未被開啟 】的錯誤
}

這就神奇啦,錯誤訊息竟然不一樣,,中英文錯誤訊息如下:

ORA-6413: 連線未被開啟
ORA-06413: Connection not open

多一條錯誤訊息就多一條線索,對追 Code 絕對有幫助。 ( 好像在玩偵探遊戲一樣 ^^ )

這時就被我搜出一篇文章 ORA-06413: Connection not open. 答案就在其中,原來錯誤發生的原因原來是我的 ASP.NET 開發伺服器 ( WebDev.WebServer.EXE ) 執行檔的路徑有特殊字元導致:

C:\Program Files (x86)\Common Files\Microsoft Shared\DevServer\9.0\WebDev.WebServer.EXE

就是這該死的 (x86) 出現在路徑中,導致我的 ASP.NET 怎樣都無法連線到程式,為了驗證確定就是這問題,我試著利用 Process Explorer 找出 WebDev.WebServer.EXE 的啟動參數:

 利用 Process Explorer 找出 WebDev.WebServer.EXE 的啟動參數

並重新透過 cmd.exe (命令提示字元) 啟動 WebDev.WebServer.EXE,這時故意用「短目錄」啟動 ASP.NET 開發伺服器,如下指令:

"C:\PROGRA~2\Common Files\Microsoft Shared\DevServer\9.0\WebDev.WebServer.EX
E"  /port:5970 /path:"D:\XXXX\XXX\Website" /vpath:"/"

神奇的事這就樣發生,Oracle 資料庫竟然真的連上了!!

我的解決之道

  1. 改用 Windows 7 內建的 IIS7 進行網站執行與偵錯,不用 ASP.NET 開發伺服器了。Windows 7 內建的 IIS7 可新增多個網站,管理上也頗方便,不像 Windows XP 只能新增一個網站
  2. 改用 Visual Studio 巨集啟動 ASP.NET 開發伺服器偵錯,細節可參考我的另一篇文章:啟動 ASP.NET 偵錯模式的另一種比按下 F5 還快的方式

本次除錯心得

  • 不要鐵齒,越覺得不可能發生的地方越有可能是破案的核心關鍵!
  • 找個人聊聊你所遇到的錯誤,在互動、對話的過程中也許會想到一些你不曾想到的地方。
  • 「程式除錯」不但要有「經驗」更要有「創意」,當你擁有更多的「生活體驗」(程設的生活),相對的創意也就越多。
  • 熟悉多種除錯工具,並在工具間交互比對、驗證錯誤,一定可以看出一些端倪,但不要只是會「用」工具而已,而是要熟悉工具「背後的原理」,這樣才有助於你思考問題的本質問題背後的問題

相關連結

  

此文章由 will 發表於 2009/8/31 下午 04:48:53

永久連結 | 評論 (1) | 此文章的RSSRSS comment feed |

分類: ASP.NET | Oracle | Visual Studio

標籤: , , ,

收藏:

Outlook 無法建立工作檔。檢查暫存環境變數。

我很愛用 Ramdisk (記憶體磁碟) 當成我的系統暫存目錄,因為這真的會讓系統的執行速度快很多,我最近為了讓我的桌上型電腦(Desktop)與筆記型電腦(Notebook)的 Ramdisk 磁碟代號一致而將 Ramdisk 磁碟更換了磁碟代碼,不過這卻導致我的 Outlook 開啟後就會出現 "Outlook 無法建立工作檔。檢查暫存環境變數。" 的錯誤訊息。

Microsoft Office Outlook - Outlook 無法建立工作檔。檢查暫存環境變數。

而為了讓 Outlook 正常運作,需要手動修改機碼。先找到以下機碼:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders

然後找到 Cache 這個可擴充字串值(REG_EXPEND_SZ)名稱,並修改成你新的暫存目錄路徑即可。

若有人也想要跟我一樣修改 Gavotte Ramdisk 安裝之後的磁碟代號,可以先找到以下機碼:

HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\RRamdisk\Parameters

並找到 DriveLetter 這個字串值(REG_SZ)名稱,並修改成你想要的磁碟代碼即可,例如:G:

相關連結

  

此文章由 will 發表於 2009/4/16 下午 10:46:36

永久連結 | 評論 (0) | 此文章的RSSRSS comment feed |

分類: 系統管理 | Oracle

標籤:

收藏:

介紹好用工具:Statement Tracer for Oracle

如果你有開發 Oracle 應用程式,那麼你應該要知道有這套工具,使用 Statement Tracer for Oracle 最大的好處就在於他可以掃瞄(Sniffer)到你電腦內任何應用程式與 Oracle 資料庫之前的所有 SQL 查詢語法(Statement),所以當你懷疑你的程式到底送了什麼 SQL Statement 到 Oracle 資料庫的話 ( 例如你用 LINQ to Oracle 進行查詢 ),就可以用這套軟體幫你掃出實際進 Oracle DB 查詢的語法。

Statement Tracer for Oracle

使用 Statement Tracer for Oracle 的前提是:「任何應用程式只要是透過 SQL*Net 或 Net8 進行資料庫操作的,就可以利用 Statement Tracer for Oracle 進行紀錄。」

例如說我先將 Statement Tracer for Oracle 啟動,然後再開啟 ASP.NET 開發伺服器 執行網站時,這時就會抓到所有網站對 Oracle 所發出的任何 SQL Statement 。

Statement Tracer for Oracle

不過以我個人的使用經驗來說,好像也有許多 .NET 寫的應用程式並不是每次都可以真的抓到資料,例如我寫一支 Console Program 並且對 Oracle 進行存取時,就從未抓到資料過,不確定是什麼問題?其他連執行 ASP.NET 開發伺服器 也有抓不到資料的經驗,實在不清楚是什麼問題?若有人能知道怎麼解決的請留言告訴我,謝謝。

雖然 Statement Tracer for Oracle 有個 Troubleshooting 的功能,但是即便我的 Console Program 已經被標注綠色了,但是卻還是沒辦法抓到傳送到 Oracle 之間的指令。

Statement Tracer for Oracle :: Troubleshooting 

 Statement Tracer for Oracle :: Troubleshooting

即便如此,好像也沒有什麼其他的好工具有機會抓到應用程式送到 Oracle 的指令,要是有個 Oracle SQL Profiler 工具就好了! ^^

相關連結

  

此文章由 will 發表於 2009/2/23 下午 10:23:26

永久連結 | 評論 (1) | 此文章的RSSRSS comment feed |

分類: Oracle | 介紹好用工具

標籤:

收藏:

解決一個使用 OracleParameter 影響資料庫查詢效能的問題

我們最近有個專案遇到一個 Oracle 資料庫查詢效能的問題,由於問題有點複雜,我必須先將「前情提要」說明清楚。

運行環境

一些會用到的程式碼

以下是我使用 OracleCommand 與 OracleDataAdapter 的相關方法:

public static void FillDataTableBySQL(DataTable dt, string SQL, OracleParameter param1)
{
    OracleCommand cmd = new OracleCommand(SQL, GetConnection());
    cmd.Parameters.Add(param1);
    FillDataTableByCommand(dt, cmd);
}
public static void FillDataTableByCommand(DataTable dt, OracleCommand cmd)
{
    OracleDataAdapter da = new OracleDataAdapter(cmd);
    da.Fill(dt);
}

我用來進行資料查詢的程式碼如下:

string SQL = "SELECT * FROM mytable WHERE Field1 = :Field1";

OracleParameter param1 = new OracleParameter("Field1", OracleDbType.NVarchar2, 20);
param1.Value = "TEST";

Utils.FillDataTableBySQL(dt, SQL, param1);

各位看官目前看到這兩段程式會覺得有問題嗎?

我的 mytable 表格中有數十萬筆的資料,Field1 的索引原本沒有加上,所以這段 SQL 的查詢時間很久,大約每次查詢會花上 20 秒。

但是當我請 Oracle DBA 加上索引(INDEX)後,程式執行的查詢速度完全沒改變,每次查詢一樣會花上 20 秒,但我用 SQL Developer 工具用完全相同的 SQL 語法手動查詢資料時,每次查詢都只要 0.01 秒以內就可以查到,這真的是鬼打牆了!

我們接著開啟 ASP.NET 的 Trace 功能檢查程式中各個環節,看哪一段花費的時間最長,最後發現執行時間最長的地方在 da.Fill(dt); 這一段,但是這一段要怎麼調阿?所有的地方都執行很快,只有 da.Fill(dt); 這一段在慢,這只能讓我懷疑 SQL 語法是不是有問題,但這麼簡單的一句 SELECT 查詢有什麼好改的呢??

接著我們就測試不使用 OracleParameter 帶參數的方式寫看看,直接將 SQL 傳進 OracleCommand 進行查詢,用自行組合 SQL 字串的方式寫,結果速度奇快,跟使用 SQL Developer 工具的查詢速度如出一轍,但我再怎麼樣都不能接受用自行組合 SQL 字串的方式任何查詢,所以還是繼續研究問題發生的原因與解決辦法。

說實在的,我們幾乎將所有能想到的開發方式都用上了,花了好幾天的時間一直不斷的嘗試不同的寫法,也上網找到了跟我們遇到一樣問題的討論,可惜並沒有任何實用的解答。

直到最後 (五天後) 我們終於嘗試出可以擁有正常執行效率且繼續使用 OracleParameter 的方法了:

string SQL = "SELECT * FROM mytable WHERE Field1 = :Field1";

OracleParameter param1 = new OracleParameter("Field1", "TEST");

Utils.FillDataTableBySQL(dt, SQL, param1);

我不知道該說些什麼,因為怎麼想都覺得沒道理阿,這兩個寫法到底哪裡不一樣阿!?

  1. 一個是先 new 一個 OracleParameter 並指定欄位、型態、與大小,然後再設定其值。
  2. 一個是直接 new 一個 OracleParameter 並指定欄位與值。

為什麼用了第一種方法感覺上沒使用「索引」進行查詢,而用了第二種雷同的方法就會使用索引呢?

光這個問題搞了我們五天時間耶,這到底是 ODP.NET 的 Bug?還是 Oracle Database Server 的問題呢?有沒有人可以告訴我呢?

總之問題圓滿解決,也可以給客戶一個交代了,但心中依然留存一團迷霧(mist),留待日後再研究吧......

  

此文章由 will 發表於 2009/1/22 上午 11:07:14

永久連結 | 評論 (14) | 此文章的RSSRSS comment feed |

分類: .Net | Oracle

標籤: , , , ,

收藏:

介紹好用工具:Oracle SQL Developer

我們一直以來就很少使用 Oracle 資料庫,一年下來也頂多 1 ~ 2 個案子採用 Oracle 的資料庫,所以一直都對 Oracle 資料庫的操作不太熟悉,尤其是用 Oracle 內建的那些超難用工具,更是不想親近,太不人性了。不過今年 Oracle 終於推出了一套 SQL Developer 資料庫管理工具,雖然還是比 Management Studio 遜色很多,不過終究像是個人用的管理工具了。

這套 SQL Developer 資料庫管理工具也是有些與 Management Studio 不同的特色,其中我覺得最大的不同在於 SQL Developer 資料庫管理工具可以不止管理 Oracle 資料庫,甚至還可以管理 SQL ServerMySQL 以及所有支援 JDBC Driver 的資料庫。

另外像是跨平台執行能力(Windows, Linux, Mac OS)、支援 CVSSubversion 版本管理、資料庫結構比對(Schema Diff)、匯入匯出資料、...等等都是不錯個功能。

當你下載 SQL Developer 資料庫管理工具後,免安裝、直接點選 sqldeveloper.exe 就可以立即執行,軟體的使用我就不多說了,各位可以自行研究,比較特別要講的是如何安裝 JDBC driver 以支援各種不同的資料庫管理。

若要讓 SQL Developer 資料庫管理工具支援 Microsoft SQL Server 管理,可以先到 jTDS JDBC Driver 網站下載 JDBC driver,下載後解壓縮 jtds-1.2.2.jar 檔案並置於 [SQL Developer 安裝目錄]\jdbc\lib 目錄下。

若要讓 SQL Developer 資料庫管理工具支援 MySQL 管理,可以到 MySQL Connector/J 5.1 下載 JDBC driver,下載後解壓縮 mysql-connector-java-5.1.7-bin.jar 檔案並置於 [SQL Developer 安裝目錄]\jdbc\lib 目錄下。

之後就要進 SQL Developer 資料庫管理工具的 Tools 選單中選取 Preferences 設定 Third Party JDBC Drivers 項目,並點選 Add Entry 新增 JDBC driver 的 *.jar 檔。

進 SQL Developer 資料庫管理工具的 Tools 選單中選取 Preferences    選取 Preferences 設定 Third Party JDBC Drivers

之後,選取你的 jar 檔(一次選一個)

選取 jar 檔

然後再新增連線

Oracle SQL Developer - 新增連線

此時就可以看到各種資料庫的頁籤了,不過缺點是在設定 Microsoft SQL Server 時只能使用 TCP/IP 連線,無法使用 Named Pipe 設定連線。

Oracle SQL Developer - New / Select Database Connection

相關連結

  

此文章由 will 發表於 2008/11/18 上午 12:38:43

永久連結 | 評論 (8) | 此文章的RSSRSS comment feed |

分類: MySQL | Oracle | SQL Server | 介紹好用工具

標籤: ,

收藏: