亚洲综合原千岁中文字幕_国产精品99久久久久久久vr_无码人妻aⅴ一区二区三区浪潮_成人h动漫精品一区二区三

主頁 > 知識庫 > 在ASP.NET 2.0中操作數據之五十七:在分層架構中緩存數據

在ASP.NET 2.0中操作數據之五十七:在分層架構中緩存數據

熱門標簽:西寧呼叫中心外呼系統線路商 臨沂智能電話機器人加盟 400電話辦理怎么樣 外呼電話機器人成本 網絡電話外呼系統上海 地圖標注軟件免費下載 蘇州如何辦理400電話 聯通官網400電話辦理 百應電話機器人外呼系統

導言:

  正如前面章節(jié)所言,緩存ObjectDataSource的數據只需要簡單的設置一些屬性。然而,它是在表現層對數據緩存,這就與ASP.NET page頁面緩存策略(caching policies)緊密的耦合(tightly couples)起來。我們對體系機構分層的原因之一便是打破這種耦合。拿業(yè)務邏輯層為例,將業(yè)務邏輯從ASP.NET頁面脫離出來;而數據訪問層將數據訪問的細節(jié)ASP.NET頁面脫離出來。從某種意義來說,將業(yè)務邏輯和數據訪問細節(jié)脫離出來是首先,這樣的話使系統更易讀、易維護、易修改,便于按模塊分工—比如,表現層的開發(fā)者對數據庫的細節(jié)不甚了解也不妨礙其開發(fā)工作。當然,將緩存策略從表現層脫離出來也有類似的好處。

  本文我們將對層次機構進行擴充,新添一個緩存層(Caching Layer,簡稱CL)以實施緩存策略。該緩存層包括一個ProductsCL類,該類用類似 GetProducts(), GetProductsByCategoryID(categoryID)等方法來訪問產品信息。調用這些方法時先從內存檢索數據,如果內存為空則調用業(yè)務邏輯層BLL里的ProductsBLL類的相應方法,再從數據訪問層DAL返回獲取的數據。該ProductsCL類的方法從業(yè)務邏輯層BLL獲取數據后先對數據緩存后再返回。

如圖1所示,緩存層CL位于表現層和業(yè)務邏輯層。


圖1:在我們的體系結構中緩存層(CL)是單獨的一層

第一步:創(chuàng)建緩存層的類

  在本文,我們創(chuàng)建的緩存層僅僅包含一個ProductsCL類,它只有幾個方法。
  完整的緩存層還應該包含CategoriesCL, EmployeesCL, 和SuppliersCL類。有了業(yè)務邏輯層BLL和數據訪問層DAL,緩存層完全可以當成一個單獨的類庫工程(Class Library project),不過我們將它作為App_Code文件夾里的一個類來處理。

  為了更好的將緩存層類和DAL類、BLL類區(qū)分開,我們在App_Code文件夾里創(chuàng)建一個新的子文件夾。在資源管理器里右擊App_Code文件夾,選擇“新文件夾”,命名為CL,在里面添加新類ProductsCL.cs


圖2:添加名為CL的文件夾和名為ProductsCL.cs的類

  跟BLL里的ProductsBLL類一樣,ProductsCL類應該包含相同的數據訪問和修改方法。不過在本文,我們只創(chuàng)建GetProducts()方法(在第3步)和GetProductsByCategoryID(categoryID)方法(在第4步)。你可以在空閑的時候對ProductsCL類進行完善,并創(chuàng)建相應的CategoriesCL, EmployeesCL和 SuppliersCL類

第二步:對Data Cache進行讀和寫

  ObjectDataSource的緩存屬性使用ASP.NET data cache來存儲從BLL獲取的數據。要訪問data cache,可以從ASP.NET頁面的code-behind classes類或體系結構層(architecture)的類來訪問。要通過ASP.NET頁面的code-behind classes類對data cache進行讀寫,可使用如下模式:

// Read from the cache(讀)
object value = Cache["key"];
// Add a new item to the cache(寫)
Cache["key"] = value;
Cache.Insert(key, value);
Cache.Insert(key, value, CacheDependency);
Cache.Insert(key, value, CacheDependency, DateTime, TimeSpan);

  Cache class類的Insert方法可以有很多的重載。Cache["key"] = value 和 Cache.Insert(key, value)是相同的,都是向cache添加一個條目(item),不過沒有指定expiry(可以理解為緩存持續(xù)時間)。更具代表性的是,在我們向cache添加條目的時候指定一個expiry,它要么是dependency(從屬體),要么是time-based expiry,又或者兩者兼而有之,比如上面的最后2個表達式。

  如果所需的數據存儲在內存的話,首先調用緩存層的方法返回數據。如果不在內存的話就調用BLL里相應的方法。數據先緩存再返回。就像下面的流程表解析的一樣:


圖3:如果數據存在于內存的話就調用緩存層的方法。

上圖的流程可用如下的模式:

Type instance = Cache["key"] as Type;
if (instance == null)
{
 instance = BllMethodToGetInstance();
 Cache.Insert(key, instance, ...);
}
return instance;

  其中,Type是緩存在內存中的數據的類型——具體到本文,也就是Northwind.ProductsDataTable;此外,key用于唯一地標識緩存的每一個條目。如果指定了key值的那個條目不在內存中,那么instance就為null,然后用BLL類的某恰當的方法來檢索數據,將獲得的數據緩存到內存。將instance返回后,它將包含一個對數據的引用(reference to the data),數據要么來自內存,要么是BLL類的返回數據。

  當訪問內存時,請務必使用上述模式。下面的這個模式,咋一看好像和上面的模式一模一樣,但是有一個細微的區(qū)別,它存在一個race condition(可以理解為不易察覺的隱式缺陷)。race condition很難調試,因為它只是偶爾發(fā)生,而且再次發(fā)生的可能性也小。如下:

if (Cache["key"] == null)
{
 Cache.Insert(key, BllMethodToGetInstance(), ...);
}
return Cache["key"];

  再一個就是,上述模式不是在局部變量里存儲緩存條目的引用,而是在條件語句里直接訪問數據,在return語句里直接返回數據。設想這種情況,開始運行代碼時Cache["key"]是non-null的,但在運行return語句前,系統將其從內存里清除掉,那么代碼就會返回一個null值,而不是我們期望的某種類型的對象。

  注意:如果僅僅是對data cache進行讀或寫訪問,你沒有必要進行同步訪問(synchronize thread access);當然,如果你需要對內存里的數據進行多重操作(multiple operations),你還是應該實施鎖定(lock),或其它的機制。

如果要從data cache里清除某個條目,可以用Remove方法,比如:

Cache.Remove(key);

第三步:從ProductsCL類返回產品信息

  在本文,我們要在ProductsCL類里用2個方法來返回產品信息: GetProducts()和 GetProductsByCategoryID(categoryID). 和業(yè)務邏輯層里的ProductsBL類相似,緩存層里的GetProducts()方法返回一個Northwind.ProductsDataTable對象,來獲取所有產品的信息;而GetProductsByCategoryID(categoryID)方法返回的是某個特定類別的所有產品。

如下的代碼是ProductsCL類里的部分方法:

[System.ComponentModel.DataObject]
public class ProductsCL
{
 private ProductsBLL _productsAPI = null;
 protected ProductsBLL API
 {
 get
 {
 if (_productsAPI == null)
 _productsAPI = new ProductsBLL();

 return _productsAPI;
 }
 }
 
 [System.ComponentModel.DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
 public Northwind.ProductsDataTable GetProducts()
 {
 const string rawKey = "Products";

 // See if the item is in the cache
 Northwind.ProductsDataTable products = _
 GetCacheItem(rawKey) as Northwind.ProductsDataTable;
 if (products == null)
 {
 // Item not found in cache - retrieve it and insert it into the cache
 products = API.GetProducts();
 AddCacheItem(rawKey, products);
 }

 return products;
 }
 
 [System.ComponentModel.DataObjectMethodAttribute(DataObjectMethodType.Select, false)]
 public Northwind.ProductsDataTable GetProductsByCategoryID(int categoryID)
 {
 if (categoryID  0)
 return GetProducts();
 else
 {
 string rawKey = string.Concat("ProductsByCategory-", categoryID);

 // See if the item is in the cache
 Northwind.ProductsDataTable products = _
 GetCacheItem(rawKey) as Northwind.ProductsDataTable;
 if (products == null)
 {
 // Item not found in cache - retrieve it and insert it into the cache
 products = API.GetProductsByCategoryID(categoryID);
 AddCacheItem(rawKey, products);
 }

 return products;
 }
 }
}

  首先,注意運用到類(class)和方法(methods)上的屬性 DataObject和 DataObjectMethodAttribute ;這些屬性服務于ObjectDataSource的設置向導,指出那些類和方法應該出現在向導的設置步驟里。因為ObjectDataSource控件要在表現層訪問這些類和方法,所以我添加了這些屬性,方便向導設置。關于這些屬性及其作用,請參閱本教程第2章《創(chuàng)建一個業(yè)務邏輯層》。

  在GetProducts() 和 GetProductsByCategoryID(categoryID)方法里,GetCacheItem(key)返回的數據賦值給一個局部變量。GetCacheItem(key)方法根據指定的key值在內存查找對應的緩存條目;如果沒找到,則用ProductsBLL類里相應的方法來檢索數據,并用AddCacheItem(key, value)方法將獲取的數據緩存到內存。

GetCacheItem(key) 和 AddCacheItem(key, value)方法分別對data cache進行讀、寫操作。GetCacheItem(key)相對簡單,它根據傳入的key值,從Cache類返回數據,如下:

private object GetCacheItem(string rawKey)
{
 return HttpRuntime.Cache[GetCacheKey(rawKey)];
}

private readonly string[] MasterCacheKeyArray = {"ProductsCache"};
private string GetCacheKey(string cacheKey)
{
 return string.Concat(MasterCacheKeyArray[0], "-", cacheKey);
}

  GetCacheItem(key)并沒有直接使用我們提供的key值,而是調用GetCacheKey(key)方法,因為該方法根據“ProductsCache-”返回key;在上述代碼中,MasterCacheKeyArray用于存儲字符串“ProductsCache”。當然,AddCacheItem(key, value)方法也會用到MasterCacheKeyArray,我們稍后會看到。

  在ASP.NET頁面后臺代碼類(code-behind class),我們可以使用Page類的Cache屬性來訪問data cache ,就像我們在第2步里的表達式:Cache["key"] = value一樣;而在體系結構的類(注:具體到本文,就是緩存層類(ProductsCL),我們可以通過2種方式來訪問:HttpRuntime.Cache 或 HttpContext.Current.Cache ;在Peter Johnson的博客里有一篇文章《HttpRuntime.Cache vs. HttpContext.Current.Cache》(http://weblogs.asp.net/pjohnson/archive/2006/02/06/437559.aspx),探討了HttpRuntim與相對于HttpContext.Current的優(yōu)點;在此,我們的ProductsCL類將使用HttpRuntime.
注意:如果你是使用的類庫工程(Class Library projects),一定要記得引用System.Web才能使用HttpRuntime 和 HttpContext類。

  如果沒有在內存找到數據,ProductsCL類將從業(yè)務邏輯層BLL獲取數據,并使用AddCacheItem(key, value)對數據進行緩存,可以用下面的代碼向內存添加緩存數據,其緩存時間為60秒:

const double CacheDuration = 60.0;

private void AddCacheItem(string rawKey, object value)
{
 HttpRuntime.Cache.Insert(GetCacheKey(rawKey), value, null,
 DateTime.Now.AddSeconds(CacheDuration), Caching.Cache.NoSlidingExpiration);
}

  其中,DateTime.Now.AddSeconds(CacheDuration)指定了緩存時間—60秒;而 System.Web.Caching.Cache.NoSlidingExpiration指明了不存在可變緩存時間(no sliding expiration).雖然Insert()方法可以包含絕對時間和可變時間(absolute and sliding expiry)2種定義緩存時間的輸入參數,但是你只能指定其中一個,如果你同時指定絕對時間和可變時間2個參數的話,Insert()方法會拋出一ArgumentException 異常。
注意:直接執(zhí)行AddCacheItem(key, value)方法會有一些弊端,我們將在第4步解釋并修正。

第4步:當數據被修改時使緩存失效

  除了數據檢索方法外,緩存層還應該包含插入、更新、刪除數據的方法。緩存層的數據修改方法并不是修改緩存的數據,而是調用業(yè)務邏輯層的相應方法,然后使緩存數據失效。就像前面章節(jié)探討的那樣,當激活ObjectDataSource的緩存屬性時,便可調用它的Insert, Update或Delete方法。

下面的UpdateProduct方法,說明了如何在緩存層CL執(zhí)行數據修改方法:

[System.ComponentModel.DataObjectMethodAttribute(DataObjectMethodType.Update, false)]
public bool UpdateProduct(string productName, decimal? unitPrice, int productID)
{
 bool result = API.UpdateProduct(productName, unitPrice, productID);

 // TODO: Invalidate the cache

 return result;
}

  在業(yè)務邏輯層的方法返回數據以前,我們需要將緩存的數據失效。不過,這并非易事,無論ProductsCL class's GetProducts()還是GetProductsByCategoryID(categoryID)都會向內存添加條目,并且GetProductsByCategoryID(categoryID)方法會為每種類別添加幾個條目(因為每種類別有幾種甚至更多的產品)。

  要使緩存數據失效,我們需要將ProductsCL類添加的所有條目刪除。為此,在AddCacheItem(key, value)方法里,當添加條目時為其指定一個緩存從屬體(cache dependency)。一般來說,緩存從屬體可以是內存里的另一個條目;文件系統里的一個文件;又或者是Microsoft SQLServer database數據庫里的數據。當從屬體發(fā)生改變,或者從內存里移除時,其對應的緩存條目會自動的從內存刪除。在本教程,當ProductsCL類向內存添加條目時,我們創(chuàng)建一個額外的條目作為其從屬體。由此,要刪除緩存條目,僅僅移除這些從屬體即可。

  我們來更改AddCacheItem(key, value)方法,當用該方法向內存添加緩存數據時,使每個條目與一個從屬體(cache dependency)對應起來。

private void AddCacheItem(string rawKey, object value)
{
 System.Web.Caching.Cache DataCache = HttpRuntime.Cache;

 // Make sure MasterCacheKeyArray[0] is in the cache - if not, add it
 if (DataCache[MasterCacheKeyArray[0]] == null)
 DataCache[MasterCacheKeyArray[0]] = DateTime.Now;

 // Add a CacheDependency
 System.Web.Caching.CacheDependency dependency =
 new CacheDependency(null, MasterCacheKeyArray);
 DataCache.Insert(GetCacheKey(rawKey), value, dependency,
 DateTime.Now.AddSeconds(CacheDuration),
 System.Web.Caching.Cache.NoSlidingExpiration);
}

  MasterCacheKeyArray是一個字符串數組,用來存儲“ProductsCache”. 首先檢查MasterCacheKeyArray,如果其為null,用當前date和time對其賦值。然后,創(chuàng)建一個從屬體。CacheDependency類的構造器(constructor)可以有很多重載(overloads),本文使用的重載接受2個字符串數組作為輸入參數。第一個參數指定文件作為從屬體,但本文我們不大算用文件來做從屬體,所以我們將第一個輸入參數設為null;第二個參數指定cache keys作為從屬體,本文我們指定為MasterCacheKeyArray。然后將該CacheDependency傳遞給Insert方法。

對AddCacheItem(key, value)方法做了上述修改后,要使緩存失效,很簡單,將從屬體移除即可:

[System.ComponentModel.DataObjectMethodAttribute(DataObjectMethodType.Update, false)]
public bool UpdateProduct(string productName, decimal? unitPrice, int productID)
{
 bool result = API.UpdateProduct(productName, unitPrice, productID);

 // Invalidate the cache
 InvalidateCache();

 return result;
}

public void InvalidateCache()
{
 // Remove the cache dependency
 HttpRuntime.Cache.Remove(MasterCacheKeyArray[0]);
}

第五步:在表現層調用緩存層

  保存對ProductsCL類的修改,打開Caching文件夾里的FromTheArchitecture.aspx頁面,并添加一個GridView控件。從GridView控件的智能標簽里創(chuàng)建一個新的ObjectDataSource,在向導的第一步,從下拉列表里選擇ProductsCL,如下圖:


圖4:類ProductsCL包含在下拉列表里

  選定ProductsCL類后,點Next。我們可以看到在SELECT標簽里有2個選項:GetProducts() 和 GetProductsByCategoryID(categoryID)方法;而在UPDATE標簽里只有唯一的一個UpdateProduct()方法。在SELECT標簽里選擇GetProducts()方法;而在UPDATE標簽里選擇那個唯一的UpdateProduct()方法,最后點Finish。


圖5:ProductsCL類的方法包含在下拉列表里。

  完成向導后,Visual Studio會將ObjectDataSource的OldValuesParameterFormatString屬性設置為original_{0},并向GridView添加相應的列。將OldValuesParameterFormatString該為默認值{0}, 并啟用GridView控件的分頁、排序、編輯功能。由于緩存層CL的UploadProducts()方法只對產品的name 和 price進行編輯,由此需要對GridView做相應的修改以限制其只能編輯這2列。

  在前面的教程,我們指定GridView控件包含 ProductName, CategoryName,和UnitPrice3列。放心大膽的將其復制過來,這樣,GridView 和 ObjectDataSource的聲明代碼看起來應該像下面的這樣:

asp:GridView ID="Products" runat="server" AutoGenerateColumns="False"
 DataKeyNames="ProductID" DataSourceID="ProductsDataSource"
 AllowPaging="True" AllowSorting="True">
 Columns>
 asp:CommandField ShowEditButton="True" />
 asp:TemplateField HeaderText="Product" SortExpression="ProductName">
 EditItemTemplate>
 asp:TextBox ID="ProductName" runat="server"
  Text='%# Bind("ProductName") %>' />
 asp:RequiredFieldValidator ID="RequiredFieldValidator1"
  ControlToValidate="ProductName" Display="Dynamic"
  ErrorMessage="You must provide a name for the product."
  SetFocusOnError="True"
  runat="server">*/asp:RequiredFieldValidator>
 /EditItemTemplate>
 ItemTemplate>
 asp:Label ID="Label2" runat="server"
  Text='%# Bind("ProductName") %>'>/asp:Label>
 /ItemTemplate>
 /asp:TemplateField>
 asp:BoundField DataField="CategoryName" HeaderText="Category"
 ReadOnly="True" SortExpression="CategoryName" />
 asp:TemplateField HeaderText="Price" SortExpression="UnitPrice">
 EditItemTemplate>
 $asp:TextBox ID="UnitPrice" runat="server" Columns="8"
  Text='%# Bind("UnitPrice", "{0:N2}") %>'>/asp:TextBox>
 asp:CompareValidator ID="CompareValidator1" runat="server"
  ControlToValidate="UnitPrice" Display="Dynamic"
  ErrorMessage="You must enter a valid currency value with
  no currency symbols. Also, the value must be greater than
  or equal to zero."
  Operator="GreaterThanEqual" SetFocusOnError="True"
  Type="Currency" ValueToCompare="0">*/asp:CompareValidator>
 /EditItemTemplate>
 ItemStyle HorizontalAlign="Right" />
 ItemTemplate>
 asp:Label ID="Label1" runat="server"
  Text='%# Bind("UnitPrice", "{0:c}") %>' />
 /ItemTemplate>
 /asp:TemplateField>
 /Columns>
/asp:GridView>

asp:ObjectDataSource ID="ProductsDataSource" runat="server"
 OldValuesParameterFormatString="{0}" SelectMethod="GetProducts"
 TypeName="ProductsCL" UpdateMethod="UpdateProduct">
 UpdateParameters>
 asp:Parameter Name="productName" Type="String" />
 asp:Parameter Name="unitPrice" Type="Decimal" />
 asp:Parameter Name="productID" Type="Int32" />
 /UpdateParameters>
/asp:ObjectDataSource>

  這樣,我們該頁面就使用了緩存層。為實地演示緩存,在ProductsCL類的GetProducts() 和 UpdateProduct()方法里設置斷點(breakpoints),在瀏覽器里訪問該頁面,當排序或分頁時就會執(zhí)行這些代碼,從內存獲取數據。然后更新一條記錄,注意由于緩存失效,將從業(yè)務邏輯層BLL獲取數據并綁定到GridView。
注意:從本文download鏈接下載的緩存層并不完善。它只包含了一個ProductsCL類,它只包含幾個方法。此外,只有一個ASP.NET頁面(~/Caching/FromTheArchitecture.aspx)使用了緩存層CL,而其它的頁面都是直接調用業(yè)務邏輯層BLL。如果打算在你的應用程序里使用緩存層CL,那么頁面層的所有調用都應該先訪問緩存層CL。

總結:

  雖然可以在ASP.NET 2.0的表現層對SqlDataSource 和 ObjectDataSource控件實施緩存,但更理想的做法是在體系單獨分層來達到緩存的目的。在本文,我們在表現層和業(yè)務邏輯層之間創(chuàng)建了一個緩存層,該緩存層包含的類和方法與現有的業(yè)務邏輯層所包含的類和方法類似。當然,也是在表現層調用。

  本示例及前面教程處理的是“觸發(fā)裝載”(reactive loading)—也就是說當發(fā)現請求的數據沒在內存后將數據裝載進內存。其實數據也可以“預裝載”(proactively loaded)進內存—也就是說在數據實際請求之前將其預先裝載進內存。在下一篇文章我們將看到預裝載的情形——在應用程序啟動的時候如何將靜態(tài)值(static values)裝載進內存。

  祝編程快樂!

作者簡介

  本系列教程作者 Scott Mitchell,著有六本ASP/ASP.NET方面的書,是4GuysFromRolla.com的創(chuàng)始人,自1998年以來一直應用 微軟Web技術。大家可以點擊查看全部教程《[翻譯]Scott Mitchell 的ASP.NET 2.0數據教程》,希望對大家的學習ASP.NET有所幫助。

您可能感興趣的文章:
  • 在ASP.NET 2.0中操作數據之五十八:在程序啟動階段緩存數據
  • 在ASP.NET 2.0中操作數據之五十九:使用SQL緩存依賴項SqlCacheDependency
  • 在ASP.NET 2.0中操作數據之六十:創(chuàng)建一個自定義的Database-Driven Site Map Provider
  • 在ASP.NET 2.0中操作數據之六十一:在事務里對數據庫修改進行封裝
  • 在ASP.NET 2.0中操作數據之六十二:GridView批量更新數據
  • 在ASP.NET 2.0中操作數據之六十三:GridView實現批量刪除數據
  • 在ASP.NET 2.0中操作數據之六十四:GridView批量添加數據
  • 在ASP.NET 2.0中操作數據之六十五:在TableAdapters中創(chuàng)建新的存儲過程
  • 在ASP.NET 2.0中操作數據之六十六:在TableAdapters中使用現有的存儲過程
  • 在ASP.NET 2.0中操作數據之六十七:在TableAdapters中使用JOINs

標簽:聊城 平涼 慶陽 海西 中衛(wèi) 臨夏 清遠 甘肅

巨人網絡通訊聲明:本文標題《在ASP.NET 2.0中操作數據之五十七:在分層架構中緩存數據》,本文關鍵詞  在,ASP.NET,2.0,中,操作,數據,;如發(fā)現本文內容存在版權問題,煩請?zhí)峁┫嚓P信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《在ASP.NET 2.0中操作數據之五十七:在分層架構中緩存數據》相關的同類信息!
  • 本頁收集關于在ASP.NET 2.0中操作數據之五十七:在分層架構中緩存數據的相關信息資訊供網民參考!
  • 推薦文章
    四虎影视精品永久免费网站 | 亚欧视频在线| 可以免费看污视频的网站| 日韩欧美一及在线播放| 午夜激情视频在线播放| 久久99这里只有精品国产| 高清一级做a爱过程不卡视频| 国产视频一区二区在线播放| 成人免费观看的视频黄页| 日本免费乱理伦片在线观看2018| 午夜家庭影院| 欧美另类videosbestsex视频| 国产视频一区在线| 亚洲天堂在线播放| 成人影视在线播放| 久久国产影视免费精品| 精品国产一区二区三区久| 国产不卡高清| 欧美一级视频免费| 欧美爱色| 国产精品1024永久免费视频| 黄色短视频网站| 成人高清护士在线播放| 超级乱淫黄漫画免费| 国产一区免费在线观看| 高清一级做a爱过程不卡视频| 天堂网中文字幕| 精品久久久久久影院免费| 国产福利免费观看| 韩国毛片免费大片| 四虎影视精品永久免费网站 | 亚洲第一色在线| 精品视频一区二区三区| 香蕉视频三级| 一级女性全黄久久生活片| 91麻豆爱豆果冻天美星空| 久久精品大片| 日本特黄特色aaa大片免费| 好男人天堂网 久久精品国产这里是免费 国产精品成人一区二区 男人天堂网2021 男人的天堂在线观看 丁香六月综合激情 | 欧美国产日韩在线| 99热精品一区| 日韩一级精品视频在线观看| 欧美1卡一卡二卡三新区| 日韩一级黄色片| 国产麻豆精品免费视频| 高清一级做a爱过程不卡视频| 国产91精品露脸国语对白| 久久精品人人做人人爽97| 麻豆系列国产剧在线观看| 韩国三级香港三级日本三级la| 青青久在线视频| 九九久久99综合一区二区| 欧美a免费| 日本在线www| 免费一级片在线| 国产a视频精品免费观看| 99久久精品国产免费| 欧美另类videosbestsex久久| 四虎精品在线观看| 欧美激情一区二区三区视频 | 中文字幕Aⅴ资源网| 亚洲www美色| 日本特黄特色aa大片免费| 国产成人精品影视| 久久99中文字幕| 国产一区精品| 九九九网站| 国产精品自拍在线| 中文字幕一区二区三区 精品 | 国产视频久久久久| 国产网站在线| 精品国产香蕉伊思人在线又爽又黄| 国产成人啪精品| 免费一级片在线| 精品视频一区二区三区免费| 美女免费毛片| 国产福利免费视频| 好男人天堂网 久久精品国产这里是免费 国产精品成人一区二区 男人天堂网2021 男人的天堂在线观看 丁香六月综合激情 | 国产不卡在线播放| 你懂的国产精品| 午夜欧美成人久久久久久| 中文字幕一区二区三区精彩视频 | 超级乱淫伦动漫| 亚洲精品久久玖玖玖玖| 亚洲天堂在线播放| 久久久久久久久综合影视网| 国产国语对白一级毛片| 日本久久久久久久 97久久精品一区二区三区 狠狠色噜噜狠狠狠狠97 日日干综合 五月天婷婷在线观看高清 九色福利视频 | 四虎精品在线观看| 国产综合91天堂亚洲国产| 免费国产在线观看| 久久国产精品自由自在| 日本免费乱人伦在线观看| 欧美一级视频免费| 国产精品免费久久| 久久99中文字幕久久| 91麻豆精品国产综合久久久| 国产视频一区二区在线播放| 国产一区二区精品久久91| 好男人天堂网 久久精品国产这里是免费 国产精品成人一区二区 男人天堂网2021 男人的天堂在线观看 丁香六月综合激情 | 精品国产一区二区三区久久久蜜臀| 亚洲第一色在线| 日韩av片免费播放| 一级女性全黄生活片免费| 日韩一级黄色片| 香蕉视频一级| 精品久久久久久免费影院| 亚久久伊人精品青青草原2020| 久久99中文字幕久久| 成人免费网站久久久| 一级女性全黄生活片免费| 黄视频网站免费观看| 成人影视在线播放| 一 级 黄 中国色 片| 日韩一级黄色片| 欧美夜夜骑 青草视频在线观看完整版 久久精品99无色码中文字幕 欧美日韩一区二区在线观看视频 欧美中文字幕在线视频 www.99精品 香蕉视频久久 | 日韩专区第一页| 久久精品道一区二区三区| 成人免费观看网欧美片| 成人影院一区二区三区| 天天做人人爱夜夜爽2020毛片| 四虎精品在线观看| 成人a大片在线观看| 国产精品123| 国产国语对白一级毛片| 国产成人精品影视| 欧美a免费| 国产91精品系列在线观看| 中文字幕一区二区三区 精品 | 成人免费观看视频| 国产一区精品| 欧美a免费| 国产不卡在线看| 日本伦理片网站| 精品视频免费在线| 国产视频一区二区三区四区 | 国产伦精品一区二区三区在线观看| 免费国产在线视频| 午夜在线观看视频免费 成人| 日本免费乱理伦片在线观看2018| 天堂网中文字幕| 精品久久久久久免费影院| 欧美激情中文字幕一区二区| 99久久精品国产高清一区二区| 国产亚洲精品成人a在线| 尤物视频网站在线观看| 欧美大片aaaa一级毛片| 亚欧成人乱码一区二区| 99久久精品国产国产毛片| 精品在线观看国产| 精品久久久久久中文字幕一区| 免费国产在线观看不卡| 91麻豆高清国产在线播放| 一级毛片视频在线观看| 日韩在线观看网站| 可以免费看毛片的网站| 欧美大片aaaa一级毛片| 九九久久99| 国产一级生活片| 国产极品白嫩美女在线观看看| 日韩中文字幕一区二区不卡| 国产不卡精品一区二区三区| 韩国妈妈的朋友在线播放| 韩国妈妈的朋友在线播放| a级黄色毛片免费播放视频| 亚欧视频在线| 四虎精品在线观看| 成人a大片高清在线观看| 四虎论坛| 中文字幕Aⅴ资源网| 国产成人啪精品| 青草国产在线| 亚洲 欧美 91| 国产伦理精品| 成人免费一级毛片在线播放视频| 中文字幕一区二区三区精彩视频| 香蕉视频三级| 国产一区二区福利久久| 精品美女| 高清一级做a爱过程不卡视频| 精品国产香蕉在线播出| 国产亚洲男人的天堂在线观看| 国产视频一区二区三区四区 | 一本伊大人香蕉高清在线观看| 日韩专区在线播放| 亚洲 国产精品 日韩| 超级乱淫黄漫画免费| 二级特黄绝大片免费视频大片| 九九精品在线播放| 日韩在线观看视频免费| 日韩免费在线观看视频| 精品视频一区二区三区免费| 99久久精品费精品国产一区二区| 欧美大片毛片aaa免费看| 亚洲天堂免费| 午夜在线影院| 日本在线播放一区| 日本久久久久久久 97久久精品一区二区三区 狠狠色噜噜狠狠狠狠97 日日干综合 五月天婷婷在线观看高清 九色福利视频 | 国产精品免费精品自在线观看| 精品久久久久久中文|