1. 程式人生 > 其它 >PDF.NET的SQL日誌 ASP.net 路徑問題 詳解

PDF.NET的SQL日誌 ASP.net 路徑問題 詳解

PDF.NET(PWMIS資料開發框架)是一個基於SQL-MAP(將SQL語句對映成資料訪問程式碼)和OQL(物件化的SQL查詢表示式)技術的資料開發框架,兼有SQL和ORM的特點。儘管有些資料庫系統能夠提供SQL監視,比如SQLSERVER的事務日誌跟蹤,但好多資料庫都沒有提供這樣的功能,所以很多資料(或者ORM)框架都會有一個記錄執行的SQL日誌的功能,PDF.NET也不例外,下面講講它是怎麼實現的。

1,SQL日誌功能程式碼介紹

PDF.NET 底層訪問資料庫使用的是相容MS DAAB 3.1的AdoHelper,它在最終執行Command命令查詢的時候,呼叫了 CommandLog物件,而這個類內部有一個Stopwatch物件,用於精確記錄執行時間。

private System.Diagnostics.Stopwatch watch = null;
        /// <summary>
        /// 是否開啟執行時間記錄
        /// </summary>
        /// <param name="startStopwatch"></param>
        public CommandLog(bool startStopwatch)
        {
            if (startStopwatch)
            {
                watch = new System.Diagnostics.Stopwatch();
                watch.Start();            
            }
        }

CommandLog類公開一個WriteLog方法,記錄Ado.Net的Command物件的執行情況:

/// <summary>
        /// 寫命令日誌和執行時間(如果開啟的話)
        /// </summary>
        /// <param name="command">命令物件</param>
        /// <param name="who">呼叫命令的源名稱</param>
        public void WriteLog(IDbCommand command,string who)
        {
            CommandText = command.CommandText;
            if (SaveCommandLog)
            {
                if (watch != null)
                {
                    if ((LogExecutedTime > 0 && watch.ElapsedMilliseconds > LogExecutedTime) || LogExecutedTime==0)
                    {
                        RecordCommandLog(command, who);
                        WriteLog("Execueted Time(ms):" + watch.ElapsedMilliseconds + "rn", who);
                    }
                }
                else
                {
                    RecordCommandLog(command, who);
                }
            }
        }

在CommandDB類(AdoHelper的基類)的相關資料訪問方法內,如下呼叫CommandLog類:

/// <summary>
        /// 根據查詢返回資料閱讀器物件
        /// </summary>
        /// <param name="SQL">SQL</param>
        /// <param name="commandType">命令型別</param>
        /// <param name="cmdBehavior">對查詢和返回結果有影響的說明</param>
        /// <param name="parameters">引數陣列</param>
        /// <returns>資料閱讀器</returns>
        protected virtual IDataReader ExecuteDataReader(ref string SQL, CommandType commandType, CommandBehavior cmdBehavior,ref IDataParameter[] parameters)
        {
            IDbConnection conn=GetConnection();
            IDbCommand cmd=conn.CreateCommand ();
            CompleteCommand(cmd,ref SQL,ref commandType,ref parameters);
            CommandLog cmdLog = new CommandLog(true);
            IDataReader reader=null;
            try
            {
                //如果命令物件的事務物件為空,那麼強制在讀取完資料後關閉閱讀器的資料庫連線 2008.3.20
                if(cmd.Transaction ==null && cmdBehavior==CommandBehavior.Default )
                    cmdBehavior=CommandBehavior.CloseConnection ;
                reader = cmd.ExecuteReader (cmdBehavior);
            }
            catch(Exception ex)
            {
                ErrorMessage=ex.Message ;
                //只有出現了錯誤而且沒有開啟事務,可以關閉連結
                if(cmd.Transaction==null && conn.State ==ConnectionState.Open )
                    conn.Close ();
                
                bool inTransaction = cmd.Transaction == null ? false : true;
                CommandLog.Instance.WriteErrLog(cmd, "AdoHelper:" + ErrorMessage);
                if (OnErrorThrow)
                {
                    throw new QueryException(ex.Message, cmd.CommandText, commandType, parameters, inTransaction, conn.ConnectionString);
                }
            }
            cmdLog.WriteLog(cmd, "AdoHelper");
            return reader;
        }

2,SQL日誌功能使用配置

使用SQL日誌很簡單,只需要在應用程式配置檔案中做如下配置即可,注意看配置中的註釋:

<!--PDF.NET SQL 日誌記錄配置(for 4.0)開始
        記錄執行的SQL語句,關閉此功能請將SaveCommandLog 設定為False,或者設定DataLogFile 為空;
        如果DataLogFile 的路徑中包括~符號,表示SQL日誌路徑為當前Web應用程式的根目錄;
        如果DataLogFile 不為空且為有效的路徑,當系統執行SQL出現了錯誤,即使SaveCommandLog 設定為False,會且僅僅記錄出錯的這些SQL語句;
        如果DataLogFile 不為空且為有效的路徑,且SaveCommandLog 設定為True,則會記錄所有的SQL查詢。
        在正式生產環境中,如果不需要除錯系統,請將SaveCommandLog 設定為False 。
    -->
    <add key="SaveCommandLog" value="True"/>
    <add key="DataLogFile" value="~SqlLog.txt"/>
    <!--LogExecutedTime 需要記錄的時間,如果該值等於0會記錄所有查詢,否則只記錄大於該時間的查詢。單位毫秒。-->
    <add key="LogExecutedTime" value ="300"/>
    <!--LogBufferCount 日誌資訊快取的數量,如果該值等於0會立即寫入日誌檔案,預設快取20條資訊;注意一次查詢可能會寫入多條日誌資訊-->
    <add key="LogBufferCount" value ="20"/>
<!--PDF.NET SQL 日誌記錄配置 結束-->

注意:日誌路徑可以使用ASP.NET的伺服器路徑符號“~”,該符號的具體使用說明是:

ASP.NET 包括了 Web 應用程式根目錄運算子 (~),當您在伺服器控制元件中指定路徑時可以使用該運算子。ASP.NET 會將 ~ 運算子解析為當前應用程式的根目錄。可以結合使用 ~ 運算子和資料夾來指定基於當前根目錄的路徑。 下面的示例演示了使用 Image 伺服器控制元件時用於為影象指定根目錄相對路徑的 ~ 運算子。在此示例中,無論頁面位於網站中的什麼位置,都將從位於 Web 應用程式根目錄下的 Images 資料夾中直接讀取影象檔案。 <asp:image runat="server" id="Image1" ImageUrl="~/Images/SampleImage.jpg" />可以在伺服器控制元件中的任何與路徑有關的屬性中使用 ~ 運算子。~ 運算子只能為伺服器控制元件識別,並且位於伺服器程式碼中。不能將 ~ 運算子用於客戶端元素。

詳細內容請看

ASP.net 路徑問題 詳解

3,檢視SQL日誌檔案

根據配置檔案中配置的SQL日誌地址,我們檢視一下它的內容,看它到底記錄了什麼內容:

//2011/5/9 14:48:42 @AdoHelper 執行命令:
SQL="SELECT * FROM [JJGaiKuang] (@fundCompany,@fundType,@IsConsignment,@managerID,@openState,@bankName,@Tzfg)"
//命令型別:Text
//7個命令引數:
Parameter["@fundCompany"]    =    ""              //DbType=AnsiString
Parameter["@fundType"]    =    ""              //DbType=AnsiString
Parameter["@IsConsignment"]    =    "是"              //DbType=AnsiString
Parameter["@managerID"]    =    ""              //DbType=AnsiString
Parameter["@openState"]    =    ""              //DbType=AnsiString
Parameter["@bankName"]    =    "中國銀行"              //DbType=AnsiString
Parameter["@Tzfg"]    =    ""              //DbType=AnsiString
//2011/5/9 14:48:42 @AdoHelper :Execueted Time(ms):607

//2011/5/9 14:48:59 @AdoHelper 執行命令:
SQL="SELECT * FROM [GetFundTrend_FundAnalysis_FundFeat] (@currentJJDM,@OtherJJDM)"
//命令型別:Text
//2個命令引數:
Parameter["@currentJJDM"]    =    "KF0003"              //DbType=AnsiString
Parameter["@OtherJJDM"]    =    "000001,399001,H11020,000300"              //DbType=AnsiString
//2011/5/9 14:48:59 @AdoHelper :Execueted Time(ms):369

//2011/5/9 14:49:00 @AdoHelper 執行命令:
SQL="SELECT a.id,a.基金名稱,round(a.收益率*100,2) 收益率 FROM [GetFundOfTypeNew](@jjdm,@startDate,@endDate,@type) as a"
//命令型別:Text
//4個命令引數:
Parameter["@jjdm"]    =    "KF0003"              //DbType=AnsiString
Parameter["@startDate"]    =    "2011-02-06"              //DbType=AnsiString
Parameter["@endDate"]    =    "2011-05-06"              //DbType=AnsiString
Parameter["@type"]    =    "三個月"              //DbType=AnsiString
//2011/5/9 14:49:00 @AdoHelper :Execueted Time(ms):310

//2011/5/9 14:49:00 @AdoHelper 執行命令:
SQL="SELECT * FROM [GetFundNotice](@jjdm) order by 公告時間 desc"
//命令型別:Text
//1個命令引數:
Parameter["@jjdm"]    =    "KF0003"              //DbType=AnsiString
//2011/5/9 14:49:00 @AdoHelper :Execueted Time(ms):389

從日誌檔案可以看出,程式記錄了詳細的SQL資訊,包括SQL文字和引數值,還有執行時間,本示例檔案中僅僅記錄了執行超過300毫秒的查詢。

通過框架的SQL日誌功能,可以隨時開啟或者關閉日誌,檢視日誌詳細資訊,從而為系統性能優化提供依據。

注:本功能的完全支援僅在框架版本 4.1之後,之前的版本不支援 LogExecutedTime 功能和“~”路徑功能。

注:日誌資訊快取數量配置,需要PDF.NET SOD框架 Ver 5.5.5 版本以後才支援。預設情況下已經開啟日誌資訊快取,所以如果你需要準確記錄全部日誌資訊,請每次使用AdoHelper物件,呼叫它的 Dispose 方法,也可以像下面這樣:

using(AdoHelper db=MyDB.GetDBHelper())
{
  DataSet result=db.ExecuteDataSet("select * from user");
}

注:在SOD ver 5.6.2.0124 版本後,如果沒有做任何日誌記錄引數的配置,在執行SQL出錯的時候,預設會記錄這些出錯的查詢資訊到  C:ProgramDataSODLog 目錄。如果配置了

<add key="DataLogFile" value="~SqlLog.txt"/>

DataLogFile 配置項,假設沒有開啟日誌記錄的配置,出錯了也會記錄錯誤資訊的日誌到這個配置項所指定的日誌檔案中。注意ASP.NET站點上,日誌檔案必須有寫入許可權。