最近在使用C#代碼連接Oracle數據庫,分為兩部分,WCF的客戶端與服務端。程序啟動與運行都沒有問題,部署到服務器上后,運行也沒有問題。但是第二天再訪問的時候,就會拋出下邊所示的異常。這是怎么回事?
Oracle.DataAccess.Client.OracleException ORA-03135: connection lost contact Process ID: 22574 Session ID: 799 Serial number: 43225 Oracle.DataAccess.Client.OracleException.HandleErrorHelper(Int32 errCode, OracleConnection conn, IntPtr opsErrCtx, OpoSqlValCtx* pOpoSqlValCtx, Object src, String procedure, Boolean bCheck) at Oracle.DataAccess.Client.OracleCommand.ExecuteReader(Boolean requery, Boolean fillRequest, CommandBehavior behavior) at Oracle.DataAccess.Client.OracleDataAdapter.Fill(DataSet dataSet, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior) at System.Data.Common.DbDataAdapter.Fill(DataSet dataSet, String srcTable)
相關的用於連接Oracle數據庫的代碼也非常典型,沒有一點復雜。
public DataSet ExcuteDataSetForOralce(string sql, CommandType type, List<OracleParameter> paras) { DataSet ds = new DataSet(); OracleCommand cmd = null; try { using (OracleConnection conn = new OracleConnection(ConnectionString)) { using (cmd = new OracleCommand(sql, conn)) { if (paras != null) { foreach (OracleParameter p in paras) { cmd.Parameters.Add(p); } } cmd.CommandType = type; OracleDataAdapter oda = new OracleDataAdapter(); oda.SelectCommand = cmd; conn.Open(); oda.Fill(ds, "tempTable"); conn.Close(); } } } catch (Exception ex) { log.Error("error", ex, LogType.Error); } return ds; }
通過多方查找,發現這並不是代碼的問題。而且Provider與數據庫連接的問題。實際上,我們new一個連接的時候,是從數據庫連接池里邊拿到的連接,這些連接放在.NET Provider里邊。Conn.Close()並不是關閉了連接,而是把連接還給了連接池。
現在的問題是Oracle Provider的問題,而不是代碼的問題。你的程序很久沒有跟數據庫交互了,數據庫服務器端就把連接的Open狀態關了,但是Provider沒有及時處理,依然給了C#代碼用,所以就拋出了這個異常。
解決辦法就是,不使用連接池,每次直接連數據庫,雖然不會出現這個問題,但是會有性能上的損失。
在app.config的配置文件中,在DataSource=((Description...)這個字符串中,加入不使用連接池。
Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=xxx)(PORT=1521)))(CONNECT_DATA =(SERVICE_NAME=xxx)(SERVER = DEDICATED)));User ID=xxx;password=xxxxx;Pooling=false;
