亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關于我們
? 蟲蟲下載站

?? core4.htm

?? Delphi4核心編程技術
?? HTM
?? 第 1 頁 / 共 2 頁
字號:
<html><head><title>第四章 BDE會話期 http://jjlzg.yeah.net</title><meta http-equiv=Content-Type content="text/html; charset=gb2312"></head><body bgcolor="#00000" text="#00cc66"><b>第四章 BDE會話期</b><br>   不管是單層、兩層還是多層的數據庫應用程序,一般都要用到BDE(BorlandDatabase Engine)。Delphi 4用TSession來管理BDE會話期對象,用TSessionList來管理和操縱一個應用程序中所有的BDE會話期對象。<br>   一般來說,并不需要顯式地把TSession構件放到窗體或數據模塊上,因為數據庫應用程序在每次啟動時會自動創建一個默認的BDE會話期對象叫Session。但如果開發的是一個多線程的數據庫應用程序,就要顯式地用到TSession構件,因為幾個線程有可能要同時連接數據庫,應當避免每次連接數據庫時都要創建應用程序的另一個實例。<br> <b>4.1 TSession</b><br>   TSession構件能夠對一個應用程序內的一組TDatabase構件提供全局控制。當創建數據庫應用程序(包括應用服務器)時,應用程序會自動創建一個默認的BDE會話期對象叫Session。在應用程序中加入新的TDatabase構件和新的數據集構件時,這些構件會自動地處于默認的BDE會話期對象即Session的控制之下。此外,BDE會話期對象還能夠提供訪問Paradox表的口令,指定網絡控制文件所在的目錄,控制數據庫的連接。<br>   除了默認的BDE會話期對象外,有些應用程序需要用到另外的TSession構件。例如,如果應用程序要并行查詢同一個數據庫,此時,每一個查詢都必須有單獨的BDE會話期。多線程的數據庫應用程序也需要有多個BDE會話期。<br>   您既可以在設計期加入TSession構件,也可以在運行期動態地創建TSession構件。<br> <b>4.1.1 默認的BDE會話期對象</b><br>   所有的數據庫應用程序都會自動包含一個默認的BDE會話期對象叫Session,它的SessionName屬性是Default。默認的BDE會話期對象能夠對所有的TDatabase構件提供全局控制,不管這些TDatabase構件是在設計期顯式地加到窗體或數據模塊上的還是在運行期動態創建的。注意:默認的BDE會話期對象在設計期是不存在的,它只存在于運行期。<br>   無論是在設計期還是在運行期加入TDatabase構件時,加入的TDatabase構件都會自動處于默認的BDE會話期對象管理之下。當然,如果您顯式地使用了多個TSession構件,您也可以設置TDatabase構件的SessionName屬性指定其中一個TSession構件。<br>   TSession最重要的屬性是KeepConnections,如果這個屬性設為True,即使當前沒有打開數據集,也保持與數據庫的連接。這樣,下次打開數據集時,就不必再登錄數據庫。<br>   注意:應用程序千萬不要試圖刪除默認的BDE會話期對象。 <br> <b>4.1.2 創建另外的BDE會話期對象</b><br>   有些情況下需要用到另外的BDE會話期對象。在設計期,您可以把一個或多個TSession構件加到窗體或數據模塊上,然后在對象觀察器中設置它們的屬性,建立事件句柄,調用它們的方法。您也可以在運行期動態地創建BDE會話期對象。<br>   要在運行期動態地創建BDE會話期對象,可以參照下列步驟:<br>   第一步是聲明一個TSession類型的變量。<br>   第二步是調用TSession的Create創建一個TSession的對象實例。Create會自動把Databases數組清為空,把KeepConnections屬性設為True,同時還把新創建的BDE會話期對象加到由Sessions管理的BDE會話期對象的列表中。<br>   第三步是設置SessionName屬性指定此BDE會話期對象的名稱,注意不能與其他BDE會話期名稱相同。TDatabase和數據集構件都是通過名稱來區分BDE會話期對象。<br>   第四步是激活此BDE會話期對象,然后設置有關屬性。<br>   下面的程序示例創建了一個BDE會話期對象,最后又刪掉了這個BDE會話期對象。<br> var SecondSession: TSession;<br> Begin<br> SecondSession := TSession.Create;<br> With SecondSession Do<br> Try<br> SessionName := 'SecondSession';<br> KeepConnections := False;<br> Open;<br> ...<br> Finally<br> SecondSession.Free;<br> End;<br> End;<br>   實際上,也可以調用TSessionList的OpenSession函數來創建BDE會話期對象,這個函數需要傳遞一個SessionName參數,指定要創建的BDE會話期對象的名稱。如果與SessionName參數匹配的BDE會話期對象已存在,這個函數就激活它。程序示例如下:<br> Var MySession : TSession;<br> MySession := Sessions.OpenSession('MySession');<br> ...<br> MySession.Free;<br> <b>4.1.3 給BDE會話期對象命名</b><br>   TSession的SessionName屬性用于給BDE會話期對象命名。對于默認的BDE會話期對象來說,它的SessionName屬性是“Default”。<br>   在同一個應用程序內,BDE會話期對象的名稱不能有重復。如果把TSession的AutoSessionName屬性設為True,Delphi 4將自動為每個BDE會話期對象指定一個相異的名稱,這樣就不用擔心重名。如果AutoSessionName屬性設為False,應用程序就必須設置SessionName屬性給每個BDE會話期對象指定一個相異的名稱。在AutoSessionName屬性設為True的情況下,不能直接修改SessionName屬性的值。<br>   不過,使用AutoSessionName屬性有許多限制。例如,如果窗體或數據模塊上有多個TSession構件,就不能把AutoSessionName屬性設為True。如果窗體或數據模塊上已經有一個TSession構件,并且它的AutoSessionName屬性設為True,就不能再把另一個TSession構件加到窗體或數據模塊上。<br>   TDatabase構件和數據集構件都有一個SessionName屬性,用于指定一個BDE會話期對象的名稱。如果它們的SessionName屬性為空,表示使用默認的BDE會話期對象。<br>   下面這個例子首先調用TSessionList的OpenSession創建一個BDE會話期對象,然后設置Database1的SessionName屬性指定剛創建的BDE會話期對象。<br> var<br> IBSession: TSession;<br> ...<br> Begin<br> IBSession := Sessions.OpenSession('InterBaseSession');<br> Database1.SessionName := 'InterBaseSession';<br> End; <br> <b>4.1.4 激活BDE會話期對象</b><br>   如果TSession的Active屬性返回True,表示BDE會話期對象處于活動狀態。如果把這個屬性設為True,將激活BDE會話期對象,并觸發OnStartup事件。<br>   激活了BDE會話期對象后,就可以調用OpenDatabase函數來連接數據庫。<br>   把Active屬性設為True,相當于調用Open。把Active屬性設為False,相當于調用Close。<br>   對于默認的BDE會話期對象即Session,最好不要把它的Active屬性設為False。<br>   當BDE會話期對象被激活時將觸發OnStartup事件,這樣就有機會設置NetFileDir、PrivateDir和ConfigMode等屬性,不過,NetFileDir和PrivateDir屬性只在訪問Paradox表才是有效的。ConfigMode屬性用于設置哪些BDE別名是可見的。<br> <b>4.1.5 KeepConnections屬性</b><br>   如果KeepConnections屬性設為True,即使當前沒有打開任何數據集,也保持與數據庫的連接。如果這個屬性設為False,當所有的數據集都關閉時,就斷開與數據庫的連接。<br>   這個屬性是針對動態生成的臨時的TDatabase構件而言的,如果顯式地使用了TDatabase構件,將以它的KeepConnections屬性為準。<br>   如果一個應用程序需要頻繁地打開和關閉所有的數據集,特別是當這些數據集是在一個遠程數服務器上時,最好把KeepConnections屬性設為True,這樣可以避免再次登錄到遠程服務器。否則,應用程序不得不重新登錄。<br>   不過,即使在KeepConnections屬性設為True的情況下,仍然可以調用DropConnections函數把空的連接斷開。所謂空的連接,是指當前并沒有打開任何數據集,但由于KeepConnections屬性設為True,仍然保持在連接狀態。<br> <b>4.1.6 打開和斷開連接</b><br>   要打開一個數據庫的連接,調用OpenDatabase函數。這個函數需要傳遞一個DatabaseName參數,用于指定要打開的數據庫的名稱,可以設為BDE別名或TDatabase構件的名稱。對于Paradox或dBASE,DatabaseName參數也可以設為表所在的路徑。<br>   下面的程序示例試圖打開別名為DBDEMOS的數據庫:<br> var<br> DBDemosDatabase: TDatabase;<br> Begin<br> DBDemosDatabase := Session.OpenDatabase('DBDEMOS');<br> ...<br> End;<br>   OpenDatabase會首先自動激活BDE會話期(如果還沒有激活的話),然后判斷DatabaseName參數是否與BDE會話期對象所管理的TDatabase構件的名稱匹配,如果沒有找到匹配的數據庫,OpenDatabase就會自動創建一個臨時的TDatabase構件。最后,OpenDatabase調用TDatabase的Open連接數據庫。<br>   OpenDatabase實際上是使一個內部的計數加1,只要這個計數大于0,數據庫就處于連接狀態。<br>   可以調用CloseDatabase函數來關閉一個數據庫。與OpenDatabase一樣,CloseDatabase也需要傳遞一個DatabaseName參數來指定要關閉的數據庫,例如:<br>   Session.CloseDatabase(DBDemosDatabase);<br>   CloseDatabase實際上是使一個內部的引用計數減1,當引用計數減到0時,數據庫才被關閉。<br>   如果DatabaseName參數指定的數據庫是由一個臨時的TDatabase構件管理的,而且KeepConnections屬性設為False,當數據庫被關閉的同時,相應的TDatabase構件也被刪除。<br>   在KeepConnections屬性設為False的情況下,對于那些臨時創建的TDatabase構件來說,如果當前沒有打開任何數據集,數據庫將自動關閉,TDatabase構件將自動刪除。對于那些顯式加到窗體或數據模塊上的TDatabase構件來說,需要調用Close才能關閉數據庫。<br>   如果要一次關閉所有的數據庫,可以把BDE會話期對象的Active屬性設為False,或者調用Close函數。把Active屬性設為False,會自動調用Close,而Close會關閉所有的數據庫,刪除所有臨時創建的TDatabase構件,然后依次調用那些顯式使用的TDatabase的Close,最后,把BDE會話期的句柄設為NIL。<br>   在打開和關閉數據庫之前,可能需要調用FindDatabase函數來查找一個特定的數據庫是否存在。FindDatabase函數需要傳遞一個DatabaseName參數,用于指定要查找的數據庫,可以設為BDE別名或者TDatabase構件的名稱。對于Paradox或dBASE表來說,可以設為表所在的路徑。如果找到的話,FindDatabase函數就返回一個TDatabase構件,否則,就返回NIL。下面這個例子試圖搜索別名為DBDEMOS的數據庫:<br> var<br> DB: TDatabase;<br> Begin<br> DB := Session.FindDatabase('DBDEMOS');<br> If (DB = nil) then DB:=Session.OpenDatabase('DBDEMOS');<br> If Assigned(DB) and DB.Active then<br>  Begin<br>   DB.StartTransaction;<br>   ...<br>  End;<br> End;<br> <b>4.2 檢索有關BDE會話期的信息</b><br>   TSession提供了許多方法用于檢索有關BDE會話期的信息如別名的參數等,下面簡單介紹這些方法。<br> .GetAliasDriverName返回一個別名的驅動程序;<br> .GetAliasNames返回所有BDE別名的列表;<br> .GetAliasParams返回一個別名的參數的列表;<br> .GetConfigParams返回配置文件中的特定信息;<br> .GetDatabaseNames返回所有BDE別名的列表(含占用的別名);<br> .GetDriverNames返回已安裝的驅動程序的列表;<br> .GetDriverParams返回一個驅動程序的參數;<br> .GetStoredProcNames返回一個數據庫中的存儲過程名;<br> .GetTableNames返回一個數據庫中的表格名。<br>   上述方法中,除了GetAliasDriverName返回一個字符串外,其他方法都是返回一個列表。下面的例子試圖檢索所有的BDE別名:<br>   var List: TStringList;<br> Begin<br> List := TStringList.Create;<br> Try<br> Session.GetDatabaseNames(List);<br> ...<br> Finally<br> List.Free;<br> End;<br> End;<br> <b>4.3 管理BDE別名</b><br>   對于BDE會話期對象來說,BDE別名特別重要,許多方法都需要傳遞一個數據庫的別名作為參數。TSession提供了管理BDE別名的功能。<br> <b>4.3.1 指定別名的可見性</b><br>   ConfigMode屬性用于設置哪些BDE別名對BDE會話期是可見的。ConfigMode屬性是一個集合,默認值是[cmAll],相當于[cfmVirtual,cfmPersistent],表示所有的別名對BDE會話期都是可見的,包括BDE配置文件中定義的別名、BDE會話期創建的專用別名。<br>   使用ConfigMode屬性的主要目的是限制別名的可見性。例如,可以把ConfigMode屬性設為[cfmVirtual],表示只能看到本BDE會話期創建的別名,不能看到其他BDE會話期創建的別名,也不能看到BDE配置文件中定義的永久別名。<br>   在BDE會話期創建的別名只存在于內存中,默認情況下,只對本BDE會話期是可見的,其他BDE會話期即使是在同一個應用程序內都無法看到這些別名。<br>   如果要使BDE會話期創建的別名能夠被所有的BDE會話期甚至其他應用程序看到,首先要調用SaveConfigFile把別名保存到BDE配置文件中,這樣,其他BDE會話期或其他應用程序才可以使用這個別名。當然,ConfigMode 屬性需要設為[cmAll]。<br> <b>4.3.2 創建、修改和刪除別名</b><br>   要創建一個SQL服務器的別名,可以調用AddAlias函數。要創建一個本地數據庫如Paradox、dBASE或ASCII文本的別名,可以調用AddStandardAlias函數。<br>   AddAlias需要傳遞三個參數,其中,Name參數用于指定名稱,Driver參數用于指定SQL Links驅動程序,List參數用于指定連接參數。程序示例如下:<br> var<br> AliasParams: TStringList;<br> Begin<br> AliasParams := TStringList.Create;<br> Try<br> With AliasParams Do<br> Begin<br> Add('OPEN MODE=READ');<br> Add('USER NAME=TOMSTOPPARD');<br> Add('SERVER NAME=ANIMALS:/CATS/PEDIGREE.GDB');<br> End;<br> Session.AddAlias('CATS', 'INTRBASE', AliasParams);<br> Finally<br> AliasParams.Free;<br> End;<br> End;<br>   與AddAlias不同的是,AddStandardAlias用于為Paradox、dBASE或文本創建別名,不需要連接參數,只需要指定一個路徑和默認的驅動程序。程序示例如下:<br>   AddStandardAlias('MYDBDEMOS', 'C:\TESTING\DEMOS\', 'Paradox');<br>   要說明的是,調用AddAlias或AddStandardAlias函數創建的別名只存在于內存中,要把別名永久地保存到BDE配置文件中,請調用SaveConfigFile函數。<br>   創建了一個別名后,就可以調用ModifyAlias來修改別名的參數。ModifyAlias需要傳遞兩個參數,一個是要修改的別名,還有一個是要修改的參數的列表。<br>   下面這個例子把CATS別名的OPEN MODE參數設為READ/WRITE:<br> var<br> List: TStringList;<br> Begin<br> List := TStringList.Create;<br> With List Do<br> Begin<br> Clear;<br> Add('OPEN MODE=READ/WRITE');<br> End;<br> Session.ModifyAlias('CATS', List);List.Free;<br> ...<br> End;<br>   雖然CATS別名的參數有幾個,但傳遞給ModifyAlias的列表中只需包含要修改的參數。<br>   要刪除一個BDE會話期創建的別名,可以調用DeleteAlias函數。DeleteAlias只需要傳遞一個參數,即要刪除的別名。<br>   注意:調用DeleteAlias函數僅僅是從內存中把一個別名刪掉,如果要刪除的別名已經永久地保存到BDE配置文件中,調用了DeleteAlias函數后還需要調用SaveConfigFile函數。<br> <b>4.4 遍歷所有的TDatabase構件</b><br>   這一節要介紹TSession的兩個屬性:Databases和DatabaseCount,用這兩個屬性可以遍歷由一個BDE會話期對象管理的所有的TDatabase構件。<br>   Databases屬性是一個數組,它的每一個元素是一個處于活動狀態的TDatabase構件,這些TDatabase構件都處于BDE會話期對象的管理之下。<br>   DatabaseCount屬性是一個整數,表明Databases數組中元素的個數。隨著數據庫的打開和關閉,DatabaseCount屬性會自動變化。例如,在KeepConnections屬性設為False并且沒有顯式使用TDatabase構件的情況下,每打開一個數據庫,DatabaseCount屬性就會加1,每關閉一個數據庫,DatabaseCount屬性就會減1。<br>   DatabaseCount屬性一般要與Databases屬性配合使用。例如,下面的代碼把所有TDatabase構件的KeepConnection屬性設為True:<br> var<br> MaxDbCount: Integer;<br> Begin<br> With Session Do<br> If (DatabaseCount > 0) then<br> For MaxDbCount := 0 to (DatabaseCount - 1) Do<br> Databases[MaxDbCount].KeepConnections:= True;<br> End;<br> <b>4.5 訪問Paradox表</b><br>   TSession的NetFileDir屬性和PrivateDir屬性只適用于Paradox表。其中,NetFileDir屬性用于指定Paradox網絡控制文件即PDOXUSRS.NET所在的目錄,凡是需要共享Paradox表的應用程序必須指定這個文件所在的目錄。PrivateDir屬性用于指定Paradox表的私有目錄,一些臨時文件就存放在私有目錄中。<br>   Delphi 4會自動從BDE配置文件中檢索網絡控制文件的位置,并把它賦給NetFileDir屬性。也可以設置這個屬性,指定另一個合法的網絡路徑。程序示例如下:<br>   Session.NetFileDir := ExtractFilePath(Application.EXEName);<br>   注意:只能在當前還沒有打開任何Paradox表的情況下修改NetFileDir屬性。<br>   如果PrivateDir屬性為空,BDE會自動把當前目錄作為私有目錄。如果要運行的應用程序在一個遠程的文件服務器上,為了避免老是讀寫文件服務器從而影響速度,最好把PrivateDir屬性設為本地的某一個驅動器。<br>   注意:不能在設計期設置PrivateDir屬性,否則,會出現“Directory Busy”的錯誤。另外,不要把PrivateDir屬性設為一個驅動器的根目錄,最好是子目錄。程序示例如下:<br>   Session.PrivateDir := 'C:\TEMP';<br> <b>4.6 口 令</b><br>   有的Paradox表和dBASE表是被口令保護的,訪問這些表時需要提供口令。TSession提供了若干個方法和一個事件用于管理口令。<br> <b>4.6.1 AddPassword</b><br>   TSession的AddPassword函數一般在訪問需要輸入口令的Paradox或dBase表之前調用,用于提供口令。AddPassword唯一的參數就是口令。程序示例如下:<br> var<br> Passwrd: String;<br> Begin<br> Passwrd := InputBox('Enter password', 'Password:', '');<br> Session.AddPassword(Passwrd);<br> Try<br>  Table1.Open<br> Except<br>   ShowMessage('Could not open table!');<br> Application.Terminate;<br> End;<br> End;<br>   上面這個例子中調用InputBox函數讓用戶輸入口令,也可以調用PasswordDialog函數,或者用TEdit構件做一個編輯框,把PasswordChar屬性設為星號。<br>   如果用PasswordDialog函數的話,需要傳遞BDE會話期對象作為參數,程序示例如下:<br> Procedure TForm1.Button1Click(Sender: TObject);<br> Begin<br> If PasswordDialog(Session) then<br>  Table1.Open<br> Else<br>  ShowMessage('No password given, could not open table!');<br> End;<br>   上述程序將打開一個“Enter password”對話框,如圖4.1所示。<br>   圖4.1 輸入口令<br>   對話框上的“Add”按鈕相當于調用AddPassword函數,“Remove”按鈕相當于調用RemovePassword函數,“Remove All”按鈕相當于RemoveAllPasswords函數。<br>   注意:要在程序中調用PasswordDialog函數,必須引用DBPWDlg單元。<br> 如果您沒有調用AddPassword或PasswordDialog函數來提供口令,當訪問有口令保護的Paradox表和dBase表時,就會自動彈出如圖4.1所示的對話框,讓用戶輸入口令。<br> 4.6.2 RemovePassword和RemoveAllPasswords<br>   TSession的RemovePassword用于刪除一個先前用AddPassword輸入的口令。RemovePassword只需要傳遞一個參數,即要刪除的口令。程序示例如下:<br>   Session.RemovePassword('1234');<br>   TSession的RemoveAllPasswords函數用于刪除先前所有輸入的口令,程序示例如下:<br>   Session.RemoveAllPasswords;<br> <b>4.6.3 OnPassword和GetPassword</b><br>   當程序試圖打開一個受口令保護的Paradox表時將觸發該事件,應當在處理這個事件的句柄中調用AddPassWord函數輸入一個口令,然后把Continue參數設為True。<br>   調用GetPassword函數也會觸發OnPassword事件。下面這個例子動態地把一個方法作為處理OnPassword事件的句柄:<br> Procedure TForm1. FormCreate(Sender: TObject);<br> Begin<br> Session.OnPassword := Password;<br> End;<br>   Password又調用InputBox函數打開一個輸入框讓用戶輸入口令,如果用戶輸入了口令的話,就把Continue參數設為True。<br> Procedure TForm1.Password(Sender: TObject; <br> var Continue: Boolean);<br> var Passwrd: String;<br> Begin<br> Passwrd := InputBox('Enter password', 'Password:', '');<br> Continue := (Passwrd > '');<br> Session.AddPassword(Passwrd);<br> End;<br>   如果用戶輸入的口令是錯誤的,則仍然不能打開Paradox表,因此,凡是要打開一個Paradox表的代碼必須能處理異常。<br>   Procedure TForm1.OpenTableBtnClick(Sender: TObject);<br> const CRLF = #13 + #10;<br> Begin<br> Try<br> Table1.Open; {將觸發OnPassword事件}<br> Except<br> On E:Exception Do<br> Begin<br> ShowMessage('Error!'+CRLF+E.Message+CRLF);<br> Application.Terminate;<br> End;<br> End;<br> End;<br> <b>4.7 管理多個BDE會話期對象</b><br>   如果要創建一個多線程的數據庫應用程序,就需要用多個TSession構件,而且必須在設計期顯式地加到窗體或數據模塊上,還要保證它們的SessionName屬性是相異的。<br>   Delphi 4用TSessionList來管理和操縱一個應用程序中所有的BDE會話期對象,并且已自動聲明了TSessionList的對象示例Sessions。<br>   如果要動態地創建一個新的BDE會話期對象,這就要用到TSessionList的OpenSession函數。這個函數只需要傳遞一個參數,即要創建的BDE會話期的名稱。程序示例如下:<br>   Sessions.OpenSession('RunTimeSession' + IntToStr(Sessions.Count + 1));<br>   上述代碼能保證BDE會話期的名稱不會與已有的BDE會話期重復。<br>   TSessionList定義了一些屬性和方法用來操縱BDE會話期對象,這里簡單介紹一下:<br> .Count 返回BDE會話期對象的個數,包括活動的和非活動的;<br> .FindSession 查找一個指定的BDE會話期對象,如果沒有找到,就返回NIL;<br> .GetSessionNames 返回所有BDE會話期對象的SessionName屬性組成的列表;<br> .List 通過這個屬性可以按名稱訪問一個BDE會話期對象;<br> .OpenSession 動態地創建一個BDE會話期對象;<br> .Sessions 通過這個屬性可以按序號訪問一個BDE會話期對象。<br>   在多線程的數據庫應用程序中,在打開一個數據庫之前,首先要檢查這個數據庫是否已經被其他線程打開。怎么檢查呢?用TSessionList的Count屬性和Sessions屬性遍歷所有的BDE會話期對象,逐個檢查每個BDE會話期對象的Databases屬性中是否包含要打開的數據庫,如果有的話,說明這個數據庫已經被某個線程打開,也就是說,不能再在這個BDE會話期內打開數據庫,您得換下一個再進行檢查。<br>   如果所有的BDE會話期對象都在使用這個數據庫,就必須創建一個新的BDE會話期對象,然后再打開數據庫。</body></html>

?? 快捷鍵說明

復制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
国产中文字幕一区| 欧美日韩免费观看一区二区三区| av一区二区三区四区| 欧美精品三级在线观看| 中文字幕欧美激情一区| 日本成人在线视频网站| 99国产精品久久| 精品免费国产二区三区| 亚洲va欧美va人人爽午夜| 成人免费高清在线| xfplay精品久久| 日韩av中文字幕一区二区三区| 91在线视频网址| 久久男人中文字幕资源站| 日本不卡一区二区| 在线观看中文字幕不卡| 中文字幕亚洲区| 成人美女视频在线观看| 国产午夜精品理论片a级大结局| 午夜精彩视频在线观看不卡| 色综合久久精品| 日韩毛片高清在线播放| www.视频一区| 国产精品福利av| 成人黄色在线网站| 国产精品盗摄一区二区三区| 国产精品91一区二区| 久久久精品免费免费| 国产精品一级二级三级| 久久蜜桃一区二区| 国产精品亚洲а∨天堂免在线| 久久麻豆一区二区| 高清视频一区二区| 中文子幕无线码一区tr| 国产成人精品亚洲日本在线桃色| 精品国产免费久久 | 日韩精品资源二区在线| 日韩在线播放一区二区| 日韩一区二区三区三四区视频在线观看 | 精品欧美一区二区久久| 精品中文字幕一区二区| 久久久久久久综合| 岛国精品一区二区| 亚洲欧美一区二区三区国产精品| 91伊人久久大香线蕉| 亚洲一区二区高清| 欧美男同性恋视频网站| 精品一区二区影视| 国产精品视频一二| 在线免费av一区| 日本女人一区二区三区| 久久美女高清视频| 91亚洲精华国产精华精华液| 午夜国产不卡在线观看视频| 一区在线观看免费| 在线影院国内精品| 日本不卡高清视频| 国产精品三级在线观看| 欧洲国内综合视频| 精品一区二区三区久久| 国产精品伦理在线| 欧美日本韩国一区二区三区视频| 精品中文字幕一区二区小辣椒| 国产精品水嫩水嫩| 欧美日韩国产中文| 大胆亚洲人体视频| 亚洲图片欧美一区| 国产欧美日韩三区| 欧美日本不卡视频| 成人v精品蜜桃久久一区| 香蕉久久一区二区不卡无毒影院 | 欧美高清你懂得| 国产99久久久国产精品潘金网站| 亚洲宅男天堂在线观看无病毒| 欧美高清视频不卡网| 成人午夜电影久久影院| 视频一区欧美日韩| 中文字幕av一区二区三区免费看| 欧美日韩你懂的| 国产精品中文有码| 亚洲高清免费在线| 国产精品久久久久影院色老大| 欧美日本在线视频| jlzzjlzz欧美大全| www.性欧美| 国产精品亚洲午夜一区二区三区 | 99re热这里只有精品免费视频| 美女国产一区二区三区| 亚洲综合免费观看高清在线观看| 国产婷婷一区二区| 欧美一区二区三区播放老司机| 91视视频在线观看入口直接观看www| 日本不卡1234视频| 亚洲国产精品久久一线不卡| 一区精品在线播放| 国产精品女人毛片| 日韩免费观看高清完整版在线观看| 色88888久久久久久影院按摩 | 亚洲免费观看在线观看| 久久久久久久电影| 久久综合久久综合久久综合| 日韩一区二区在线免费观看| 欧美日韩视频一区二区| 久久久久久97三级| 日韩欧美第一区| 911精品国产一区二区在线| 精品视频色一区| 欧美在线免费视屏| 91精品福利视频| 91亚洲男人天堂| 日本久久电影网| 欧美中文一区二区三区| 日本韩国一区二区| 欧美视频精品在线| 欧美日韩国产高清一区二区 | 99热99精品| 97se亚洲国产综合自在线观| www.在线成人| 91久久精品网| 欧美三级三级三级爽爽爽| 欧美日高清视频| 欧美精品18+| 欧美成人一区二区三区片免费 | 95精品视频在线| 一本色道久久综合狠狠躁的推荐| 91在线看国产| 在线精品视频免费播放| 欧美美女激情18p| 日韩美女一区二区三区| 久久先锋资源网| 国产精品免费人成网站| 亚洲人123区| 图片区小说区区亚洲影院| 青青草国产精品97视觉盛宴| 久久国产欧美日韩精品| 国产传媒日韩欧美成人| 色综合天天做天天爱| 欧美电影在哪看比较好| 欧美变态口味重另类| 国产精品人人做人人爽人人添| 一区二区三区日韩欧美| 丝袜美腿亚洲综合| 国精产品一区一区三区mba视频| 成人免费av网站| 欧美色精品在线视频| 久久综合中文字幕| 亚洲精品菠萝久久久久久久| 日韩av中文字幕一区二区| 成人永久免费视频| 欧美婷婷六月丁香综合色| 精品国产一区二区三区久久久蜜月| 国产欧美精品在线观看| 亚洲成人av一区二区三区| 国产乱国产乱300精品| 欧洲激情一区二区| 久久午夜羞羞影院免费观看| 亚洲一区二区三区国产| 国产精品18久久久久| 亚洲精品在线观看网站| 亚洲伊人伊色伊影伊综合网| 国产一区二区三区免费看| 色偷偷久久一区二区三区| 日韩欧美一级精品久久| 亚洲黄色小说网站| 国产一区二区视频在线播放| 欧美日韩激情在线| 国产精品无遮挡| 精品亚洲免费视频| 欧美综合欧美视频| 国产精品网友自拍| 免费一区二区视频| 欧美日韩成人综合在线一区二区| 国产欧美精品一区| 精品亚洲国内自在自线福利| 欧美美女黄视频| 亚洲黄色在线视频| 99在线视频精品| 久久久久久久久久久99999| 日本欧美一区二区| 日本精品视频一区二区| 国产精品卡一卡二| 国产精品1024| 久久久亚洲精华液精华液精华液| 三级久久三级久久| 在线观看亚洲成人| 亚洲欧美国产77777| 成人免费电影视频| 国产日韩精品一区二区三区| 国产在线精品免费av| 欧美一卡二卡在线| 日本欧美一区二区| 亚洲成人免费视| 97精品国产露脸对白| 久久久夜色精品亚洲| 视频一区二区国产| 欧美色男人天堂| 亚洲成在人线在线播放| 欧美日韩国产一区| 亚洲一本大道在线| 欧美日韩一区二区在线视频|