




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
精品文檔你我共享精品文檔你我共享AAAAAAAAAAAA數據庫訪問性能優化數據庫的連接和關閉訪問數據庫資源需要創建連接、打開連接和關閉連接幾個操作。這些過程需要多次與數據庫交換信息以通過身份驗證,比較耗費服務器資源。ASP.NET中提供了連接池(ConnectionPool)改善打開和關閉數據庫對性能的影響。系統將用戶的數據庫連接放在連接池中,需要時取出,關閉時收回連接,等待下一次的連接請求。連接池的大小是有限的,如果在連接池達到最大限度后仍要求創建連接,必然大大影響性能。因此,在建立數據庫連接后只有在真正需要操作時才打開連接,使用完畢后馬上關閉,從而盡量減少數據庫連接打開的時間,避免出現超出連接限制的情況。使用存儲過程存儲過程是存儲在服務器上的一組預編譯的SQL語句,類似于DOS系統中的批處理文件。存儲過程具有對數據庫立即訪問的功能,信息處理極為迅速。使用存儲過程可以避免對命令的多次編譯,在執行一次后其執行規劃就駐留在高速緩存中,以后需要時只需直接調用緩存中的二進制代碼即可。另外,存儲過程在服務器端運行,獨立于ASP.NET程序,便于修改,最重要的是它可以減少數據庫操作語句在網絡中的傳輸。優化查詢語句ASP.NET中ADO連接消耗的資源相當大,SQL語句運行的時間越長,占用系統資源的時間也越長。因此,盡量使用優化過的SQL語句以減少執行時間。比如,不在查詢語句中包含子查詢語句,充分利用索引等。字符串操作性能優化使用值類型的ToString方法在連接字符串時,經常使用"+"號直接將數字添加到字符串中。這種方法雖然簡單,也可以得到正確結果,但是由于涉及到不同的數據類型,數字需要通過裝箱操作轉化為引用類型才可以添加到字符串中。但是裝箱操作對性能影響較大,因為在進行這類處理時,將在托管堆中分配一個新的對象,原有的值復制到新創建的對象中。使用值類型的ToString方法可以避免裝箱操作,從而提高應用程序性能。運用StringBuilder類精品文檔你我共享精品文檔你我共享String類對象是不可改變的,對于String對象的重新賦值在本質上是重新創建了一個String對象并將新值賦予該對象,其方法ToString對性能的提高并非很顯著。在處理字符串時,最好使用StringBuilder類,其.NET命名空間是System.Text。該類并非創建新的對象,而是通過Append,Remove,Insert等方法直接對字符串進行操作,通過ToString方法返回操作結果。其定義及操作語句如下所示:intnum;System.Text.StringBuilderstr=newSystem.Text.StringBuilder();//創建字符串str.Append(num.ToString());〃添加數值numResponse.Write(str.ToString);//顯示操作結果優化Web服務器計算機和特定應用程序的配置文件以符合您的特定需要默認情況下,ASP.NET配置被設置成啟用最廣泛的功能并盡量適應最常見的方案。因此,應用程序開發人員可以根據應用程序所使用的功能,優化和更改其中的某些配置,以提高應用程序的性能。下面的列表是您應該考慮的一些選項。僅對需要的應用程序啟用身份驗證。默認情況下,身份驗證模式為Windows,或集成NTLM。大多數情況下,對于需要身份驗證的應用程序,最好在Machine.config文件中禁用身份驗證,并在Web.config文件中啟用身份驗證。根據適當的請求和響應編碼設置來配置應用程序。ASP.NET默認編碼格式為UTF-8。如果您的應用程序為嚴格的ASCII,請配置應用程序使用ASCII以獲得稍許的性能提高。考慮對應用程序禁用AutoEventWireup。在Machine.config文件中將AutoEventWireup屬性設置為false,意味著頁面不將方法名與事件進行匹配和將兩者掛鉤(例如Page_Load)。如果頁面開發人員要使用這些事件,需要在基類中重寫這些方法(例如,需要為頁面加載事件重寫Page.OnLoad,而不是使用Page_Load方法)。如果禁用AutoEventWireup,頁面將通過將事件連接留給頁面作者而不是自動執行它,獲得稍許的性能提升。從請求處理管線中移除不用的模塊。默認情況下,服務器計算機的Machine.config文件中<httpModules>節點的所有功能均保留為激活。根據應用程序所使用的功能,您可以從請求管線中移除不用的模塊以獲得稍許的性能提升。檢查每個模塊及其功能,并按您的需要自定義它。例如,如果您在應用程序中不使用會話狀態和輸出緩存,則可以從<httpModules>AAAAAA精品文檔你我共享精品文檔你我共享AAAAAAAAAAAA列表中移除它們,以便請求在不執行其他有意義的處理時,不必執行每個模塊的進入和離開代碼。一定要禁用調試模式在部署生產應用程序或進行任何性能測量之前,始終記住禁用調試模式。如果啟用了調試模式,應用程序的性能可能受到非常大的影響。對于廣泛依賴外部資源的應用程序,請考慮在多處理器計算機上啟用網絡園藝ASP.NET進程模型幫助啟用多處理器計算機上的可縮放性,將工作分發給多個進程(每個CPU一個),并且每個進程都將處理器關系設置為其CPU。此技術稱為網絡園藝。如果應用程序使用較慢的數據庫服務器或調用具有外部依賴項的COM對象(這里只是提及兩種可能性),則為您的應用程序啟用網絡園藝是有益的。但是,在決定啟用網絡園藝之前,您應該測試應用程序在網絡園中的執行情況。只要可能,就緩存數據和頁輸出ASP.NET提供了一些簡單的機制,它們會在不需要為每個頁請求動態計算頁輸出或數據時緩存這些頁輸出或數據。另外,通過設計要進行緩存的頁和數據請求(特別是在站點中預期將有較大通訊量的區域),可以優化這些頁的性能。與.NETFramework的任何Web窗體功能相比,適當地使用緩存可以更好的提高站點的性能,有時這種提高是超數量級的。使用ASP.NET緩存機制有兩點需要注意。首先,不要緩存太多項。緩存每個項均有開銷,特別是在內存使用方面。不要緩存容易重新計算和很少使用的項。其次,給緩存的項分配的有效期不要太短。很快到期的項會導致緩存中不必要的周轉,并且經常導致更多的代碼清除和垃圾回收工作。若關心此問題,請監視與ASP.NETApplications性能對象關聯的CacheTotalTurnoverRate性能計數器。高周轉率可能說明存在問題,特別是當項在到期前被移除時。這也稱作內存壓力。選擇適合頁面或應用程序的數據查看機制根據您選擇在Web窗體頁顯示數據的方式,在便利和性能之間常常存在著重要的權衡。例如,DataGridWeb服務器控件可能是一種顯示數據的方便快捷的方法,但就性能而言它的開銷常常是最大的。在某些簡單的情況下,您通過生成適當的HTML自己呈現數據可能很有效,但是自定義和瀏覽器定向會很快抵銷所獲得的額外功效。RepeaterWeb服務器控件是便利和性能的折衷。它高效、可自定義且可編程。將SqlDataReader類用于快速只進數據游標SqlDataReader類提供了一種讀取從SQLServer數據庫檢索的只進數據流的方法。如果當創建ASP.NET應用程序時出現允許您使用它的情況,則SqlDataReader類提供比DataSet類更高的性能。情況之所以這樣,是因為SqlDataReader使用SQLServer的本機網絡數據傳輸格式從數據庫連接直接讀取數據。另外,SqlDataReader類實現IEnumerable接口,該接口也允許您將數據綁定到服務器控件。有關更多信息,請參見SqlDataReader類。有關ASP.NET如何訪問數據的信息,請參見通過ASP.NET訪問數據。將SQLServer存儲過程用于數據訪問在.NETFramework提供的所有數據訪問方法中,基于SQLServer的數據訪問是生成高性能、可縮放Web應用程序的推薦選擇。使用托管SQLServer提供程序時,可通過使用編譯的存儲過程而不是特殊查詢獲得額外的性能提高。避免單線程單元(STA)COM組件默認情況下,ASP.NET不允許任何STACOM組件在頁面內運行。若要運行它們,必須在.aspx文件內將ASPCompat=true屬性包含在@Page指令中。這樣就將執行用的線程池切換到STA線程池,而且使HttpContext和其他內置對象可用于COM對象。前者也是一種性能優化,因為它避免了將多線程單元(MTA)封送到STA線程的任何調用。使用STACOM組件可能大大損害性能,應盡量避免。若必須使用STACOM組件,如在任何interop方案中,則應在執行期間進行大量調用并在每次調用期間發送盡可能多的信息。另外,小心不要在構造頁面期間創建任何STACOM組件。例如下面的代碼中,在頁面構造時將實例化由某個線程創建的MySTAComponent,而該線程并不是將運行頁面的STA線程。這可能對性能有不利影響,因為要構造頁面就必須完成MTA和STA線程之間的封送處理。<%@PageLanguage="VB"ASPCompat="true"%><scriptrunat=server>DimmyCompasnewMySTAComponent()PublicSubPage_Load()myComp.Name="Bob"EndSub</script><html><%Response.Write(myComp.SayHello)%></html>首選機制是推遲對象的創建,直到以后在STA線程下執行上述代碼,如下面的例子所示。<%@PageLanguage="VB"ASPCompat="true"%><scriptrunat=server>DimmyCompPublicSubPage_Load()myComp=newMySTAComponent()myComp.Name="Bob"EndSub</script><html><%Response.Write(myComp.SayHello)%></html>推薦的做法是在需要時或者在Page_Load方法中構造任何COM組件和外部資源。永遠不要將任何STACOM組件存儲在可以由構造它的線程以外的其他線程訪問的共享資源里。這類資源包括像緩存和會話狀態這樣的資源。即使STA線程調用STACOM組件,也只有構造此STACOM組件的線程能夠實際為該調用服務,而這要求封送處理對創建者線程的調用。此封送處理可能產生重大的性能損失和可伸縮性問題。在這種情況下,請研究一下使COM組件成為MTACOM組件的可能性,或者更好的辦法是遷移代碼以使對象成為托管對象。將調用密集型的COM組件遷移到托管代碼.NETFramework提供了一個簡單的方法與傳統的COM組件進行交互。其優點是可以在保留現有投資的同時利用新的平臺。但是在某些情況下,保留舊組件的性能開銷使得將組件遷移到托管代碼是值得的。每一情況都是不一樣的,決定是否需要遷移組件的最好方法是對Web站點運行性能測量。建議您研究一下如何將需要大量調用以進行交互的任何COM組件遷移到托管代碼。許多情況下不可能將舊式組件遷移到托管代碼,特別是在最初遷移Web應用程序時。在這種情況下,最大的性能障礙之一是將數據從非托管環境封送到托管環境。因此,在交互操作中,請在任何一端執行盡可能多的任務,然后進行一個大調用而不是一系列小調用。例如,公共語言運行庫中的所有字符串都是Unicode的,所以應在調用托管代碼之前將組件中的所有字符串轉換成Unicode格式。另外,一處理完任何COM對象或本機資源就釋放它們。這樣,其他請求就能夠使用它們,并且最大限度地減少了因稍后請求垃圾回收器釋放它們所引起的性能問題。在VisualBasic.NET或JScript代碼中使用早期綁定以往,開發人員喜歡使用VisualBasic、VBScript和JScript的原因之一就是它們所謂“無類型”的性質。變量不需要顯式類型聲明,并能夠簡單地通過使用來創建它們。當從一個類型到另一個類型進行分配時,轉換將自動執行。不過,這種便利會大大損害應用程序的性能。VisualBasic現在通過使用OptionStrict編譯器指令來支持類型安全編程。為了向后兼容,默認情況下,ASP.NET不啟用該選項。但是,為了得到最佳性能,強烈建議在頁中啟用該選項。若要啟用OptionStrict,請將Strict屬性包括在@Page指令中,或者,對于用戶控件,請將該屬性包括在@Control指令中。下面的示例演示了如何設置該屬性,并進行了四個變量調用以顯示使用該屬性是如何導致編譯器錯誤的。<%@PageLanguage="VB"Strict="true"%><%DimBDimCAsString'Thiswillcauseacompilererror.A="Hello"'Thiswillcauseacompilererror.B="World"'Thiswillnotcauseacompilererror.C=""'Butthiswillcauseacompilererror.C=0%>JScript.NET也支持無類型編程,但它不提供強制早期綁定的編譯器指令。若發生下面任何一種情況,則變量是晚期綁定的:被顯式聲明為Object。是無類型聲明的類的字段。是無顯式類型聲明的專用函數或方法成員,并且無法從其使用推斷出類型。最后一個差別比較復雜,因為如果JScript.NET編譯器可以根據變量的使用情況推斷出類型,它就會進行優化。在下面的示例中,變量A是早期綁定的,但變量B是晚期綁定的。varA;varB;A="Hello";B="World";B=0;為了獲得最佳的性能,當聲明JScript.NET變量時,請為其分配一個類型。例如,varA:String。使請求管線內的所有模塊盡可能高效請求管線內的所有模塊在每次請求中都有機會被運行。因此,當請求進入和離開模塊時快速地觸發代碼至關重要,特別是在不使用模塊功能的代碼路徑里。分別在使用及不使用模塊和配置文件時執行吞吐量測試,對確定這些方法的執行速度非常有用。使用HttpServerUtility.Transfer方法在同一應用程序的頁面間重定向采用Server.Transfer語法,在頁面中使用該方法可避免不必要的客戶端重定向。必要時調整應用程序每個輔助進程的線程數ASP.NET的請求結構試圖在執行請求的線程數和可用資源之間達到一種平衡。已知一個使用足夠CPU功率的應用程序,該結構將根據可用于請求的CPU功率,來決定允許同時執行的請求數。這項技術稱作線程門控。但是在某些條件下,線程門控算法不是很有效。通過使用與ASP.NETApplications性能對象關聯的PipelineInstanceCount性能計數器,可以在PerfMon中監視線程門控。當頁面調用外部資源,如數據庫訪問或XMLWebservices請求時,頁面請求通常停止并釋放CPU。如果某個請求正在等待被處理,并且線程池中有一個線程是自由的,那么這個正在等待的請求將開始被處理。遺憾的是,有時這可能導致Web服務器上存在大量同時處理的請求和許多正在等待的線程,而它們對服務器性能有不利影響。通常,如果門控因子是外部資源的響應時間,則讓過多請求等待資源,對Web服務器的吞吐量并無幫助。為緩和這種情況,可以通過更改Machine.config配置文件節點的maxWorkerThreads和maxIOThreads屬性,手動設置進程中的線程數限制。注意輔助線程是用來處理ASP.NET請求的,而IO線程則是用于為來自文件、數據庫或XMLWebservices的數據提供服務的。分配給這些屬性的值是進程中每個CPU每類線程的最大數目。對于雙處理器計算機,最大數是設置值的兩倍。對于四處理器計算機,最大值是設置值的四倍。無論如何,對于有四個或八個CPU的計算機,最好更改默認值。對于有一個或兩個處理器的計算機,默認值就可以,但對于有更多處理器的計算機的性能,進程中有一百或兩百個線程則弊大于利。注意進程中有太多線程往往會降低服務器的速度,因為額外的上下文交換導致操作系統將CPU周期花在維護線程而不是處理請求上。適當地使用公共語言運行庫的垃圾回收器和自動內存管理小心不要給每個請求分配過多內存,因為這樣垃圾回收器將必須更頻繁地進行更多的工作。另外,不要讓不必要的指針指向對象,因為它們將使對象保持活動狀態,并且應盡量避免含Finalize方法的對象,因為它們在后面會導致更多的工作。特別是在Finalize調用中永遠不要釋放資源,因為資源在被垃圾回收器回收之前可能一直消耗著內存。最后這個問題經常會對Web服務器環境的性能造成毀滅性的打擊,因為在等待Finalize運行時,很容易耗盡某個特定的資源。如果有大型Web應用程序,可考慮執行預批編譯每當發生對目錄的第一次請求時都會執行批編譯。如果目錄中的頁面沒有被分析并編譯,此功能會成批分析并編譯目錄中的所有頁面,以便更好地利用磁盤和內存。如果這需要很長時間,則將快速分析并編譯單個頁面,以便請求能被處理。此功能帶給ASP.NET性能上的好處,因為它將許多頁面編譯為單個程序集。從已加載的程序集訪問一頁比每頁加載新的程序集要快。批編譯的缺點在于:如果服務器接收到許多對尚未編譯的頁面的請求,那么當Web服務器分析并編譯它們時,性能可能較差。為解決這個問題,可以執行預批編譯。為此,只需在應用程序激活之前向它請求一個頁面,無論哪頁均可。然后,當用戶首次訪問您的站點時,頁面及其程序集將已被編譯。沒有簡單的機制可以知道批編譯何時發生。需一直等到CPU空閑或者沒有更多的編譯器進程(例如csc.exe(C#編譯器)或vbc.exe(VisualBasic編譯器))啟動。還應盡量避免更改應用程序的\bin目錄中的程序集。更改頁面會導致重新分析和編譯該頁,而替換\bin目錄中的程序集則會導致完全重新批編譯該目錄。在包含許多頁面的大規模站點上,更好的辦法可能是根據計劃替換頁面或程序集的頻繁程度來設計不同的目錄結構。不常更改的頁面可以存儲在同一目錄中并在特定的時間進行預批編譯。經常更改的頁面應在它們自己的目錄中(每個目錄最多幾百頁)以便快速編譯。Web應用程序可以包含許多子目錄。批編譯發生在目錄級,而不是應用程序級。不要依賴代碼中的異常因為異常大大地降低性能,所以您不應該將它們用作控制正常程序流程的方式。如果有可能檢測到代碼中可能導致異常的狀態,請執行這種操作。不要在處理該狀態之前捕獲異常本身。常見的方案包括:檢查null,分配給將分析為數字值的String一個值,或在應用數學運算前檢查特定值。下面的示例演示可能導致異常的代碼以及測試是否存在某種狀態的代碼。兩者產生相同的結果。try{result=100/num;}catch(Exceptione){result=0;}//...tothis.if(num!=0)result=100/num;elseresult=0;使用HttpResponse.Write方法進行字符串串聯該方法提供非常有效的緩沖和連接服務。但是,如果您正在執行廣泛的連接,請使用多個Response.Write調用。下面示例中顯示的技術比用對Response.Write方法的單個調用連接字符串更快。Response.Write("a");Response.Write(myString);Response.Write("b");Response.Write(myObj.ToString());Response.Write("c");Response.Write(myString2);Response.Write("d");除非有特殊的原因要關閉緩沖,否則使其保持打開禁用Web窗體頁的緩沖會導致大量的性能開銷。只在必要時保存服務器控件視圖狀態自動視圖狀態管理是服務器控件的功能,該功能使服務器控件可以在往返過程上重新填充它們的屬性值(您不需要編寫任何代碼)。但是,因為服務器控件的視圖狀態在隱藏的窗體字段中往返于服務器,所以該功能確實會對性能產生影響。您應該知道在哪些情況下視圖狀態會有所幫助,在哪些情況下它影響頁的性能。例如,如果您將服務器控件綁定到每個往返過程上的數據,則將用從數據綁定操作獲得的新值替換保存的視圖狀態。在這種情況下,禁用視圖狀態可以節省處理時間。默認情況下,為所有服務器控件啟用視圖狀態。若要禁用視圖狀態,請將控件的EnableViewState屬性設置為false,如下面的DataGrid服務器控件示例所示。<asp:datagridEnableViewState="false"datasource="..."runat="server"/>您還可以使用@Page指令禁用整個頁的視圖狀態。當您不從頁回發到服務器時,這將十分有用:<%@PageEnableViewState="false"%>注意@Control指令中也支持EnableViewState屬性,該指令允許您控制是否為用戶控件啟用視圖狀態。若要分析頁上服務器控件使用的視圖狀態的數量,請(通過將trace="true"屬性包括在@Page指令中)啟用該頁的跟蹤并查看ControlHierarchy表的Viewstate列。有關跟蹤和如何啟用它的信息,請參見ASP.NET跟蹤。避免到服務器的不必要的往返過程雖然您很可能希望盡量多地使用Web窗體頁框架的那些節省時間和代碼的功能,但在某些情況下卻不宜使用ASP.NET服務器控件和回發事件處理。通常,只有在檢索或存儲數據時,您才需要啟動到服務器的往返過程。多數數據操作可在這些往返過程間的客戶端上進行。例如,從HTML窗體驗證用戶輸入經常可在數據提交到服務器之前在客戶端進行。通常,如果不需要將信息傳遞到服務器以將其存儲在數據庫中,那么您不應該編寫導致往返過程的代碼。如果您開發自定義服務器控件,請考慮讓它們為支持ECMAScript的瀏覽器呈現客戶端代碼。通過以這種方式使用服務器控件,您可以顯著地減少信息被不必要的發送到Web服務器的次數。使用Page.IsPostBack避免對往返過程執行不必要的處理如果您編寫處理服務器控件回發處理的代碼,有時可能需要在首次請求頁時執行其他代碼,而不是當用戶發送包含在該頁中的HTML窗體時執行的代碼。根據該頁是否是響應服務器控件事件生成的,使用Page.IsPostBack屬性有條件地執行代碼。例如,下面的代碼演示如何創建數據庫連接和命令,該命令在首次請求該頁時將數據綁定到DataGrid服務器控件。voidPage_Load(Objectsender,EventArgse){//Setupaconnectionandcommandhere.if(!Page.IsPostBack){Stringquery="select*fromAuthorswhereFirstNamelike'%JUSTIN%'";myCommand.Fill(ds,"Authors");myDataGrid.DataBind();}}由于每次請求時都執行Page_Load事件,上述代碼檢查IsPostBack屬性是否設置為false。如果是,則執行代碼。如果該屬性設置為true,則不執行代碼。注意如果不運行這種檢查,回發頁的行為將不更改。Page_Load事件的代碼在執行服務器控件事件之前執行,但只有服務器控件事件的結果才可能在輸出頁上呈現。如果不運行該檢查,仍將為Page_Load事件和該頁上的任何服務器控件事件執行處理。當不使用會話狀態時禁用它并不是所有的應用程序或頁都需要針對于具體用戶的會話狀態,您應該對任何不需要會話狀態的應用程序或頁禁用會話狀態。若要禁用頁的會話狀態,請將@Page指令中的EnableSessionState屬性設置為false。例如:精品文檔你我共享精品文檔你我共享<%@PageEnableSessionState="false"%>注意如果頁需要訪問會話變量,但不打算創建或修改它們,則將@Page指令中的EnableSessionState屬性設置為Readonly。還可以禁用XMLWebservices方法的會話狀態。有關更多信息,請參見使用ASP.NET和XMLW
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 房做樣板間合同協議書
- 權屬責任移交清協議書
- 脫離單位協議書
- 聘請教師協議書
- 抖音號轉讓合同協議書
- 小飾品店面轉讓協議書
- 現金繼承協議書
- 糯家加盟協議書
- 磁磚合作協議書
- 無牌摩托車過戶協議書
- 二年級《道德與法治》下冊知識點
- 2024年四川省成都市中考歷史試卷真題(含答案解析)
- 2024屆四川省廣元市旺蒼縣小升初考試數學試卷含解析
- 2024CSCO結直腸癌診療指南解讀
- MOOC 信號與系統-西安電子科技大學 中國大學慕課答案
- 公需科目2023年度數字經濟與驅動發展考試題庫及答案
- 中學生英才計劃面試常見問題
- 壓力容器安全風險管控清單(日管控、周排查、月調度)
- 中小學心理健康教育指導綱要
- 嬰幼兒尿布性皮炎護理
- 國網兼職培訓師培訓課件
評論
0/150
提交評論