精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

工作日志,多租戶模式下的數據備份和遷移

存儲 存儲軟件
記錄和分享一篇工作中遇到的奇難雜癥。目前做的項目是多租戶模式。一套系統管理多個項目,用戶登錄不同的項目加載不同的數據。

 工作日志,多租戶模式下的數據備份和遷移

記錄和分享一篇工作中遇到的奇難雜癥。目前做的項目是多租戶模式。一套系統管理多個項目,用戶登錄不同的項目加載不同的數據。除了一些系統初始化的配置表外,各項目之間數據相互獨立。前期選擇了共享數據表的隔離方案,為后期的數據遷移挖了一個大坑。這里記錄填坑的思路。可能不優雅,僅供參考。

[[272545]]

多租戶

多租戶是一種軟件架構,在同一臺(組)服務器上運行單個實例,能為多個租戶提供服務。以實際例子說明,一套能源監控系統,可以為A產業園提供服務,也可以為B產業園提供服務。A的管理員登錄能源監控系統只會看到A產業園相關的數據。同樣的道理,B產業園也是一樣。多住戶模式最重要的就是數據之間的獨立。其最大的局限性在于對租戶定制化開發困難很大。適合通用的業務場景。

數據隔離方案

獨立數據庫

顧名思義,一個租戶獨享一個數據庫,其隔離級別最強,數據安全性最高,數據的備份和恢復最方便。對數據獨立性要求很高,數據的擴張性要求較多的租戶可以考慮使用。或者錢給的多也可以考慮。畢竟該模式下的硬件成本較高。代碼成本較低,Hibernate已經提供DATABASE的實現。

共享數據庫、獨立 Schema

多個租戶共有一個數據庫,每個租戶擁有屬于自己的Schema(Schema表示數據庫對象集合,它包含:表,視圖,存儲過程,索引等等對象)。其隔離級別較強,數據安全性較高,數據的備份和恢復較為麻煩。數據庫出了問題會影響到所有租戶。Hibernate也提供SCHEMA的實現。

共享數據庫、共享 Schema、共享數據表

多個租戶共享一個數據庫,一個Schema,一張數據表。各租戶之間通過字段區分。其隔離級別最低,數據安全性最低,數據的備份和恢復最麻煩(讓我哭一分鐘😭)。若一張表出現問題會影響到所有租戶。其代碼工作量也是最多,因為Hibernate(5.0.3版本)并沒有支持DISCRIMINATOR模式,目前還只是計劃支持。其模式最大的好處就是用最少的服務器支持最多的租戶。

業務場景

在我們的能源管理的系統中,多個租戶就是多個項目。將需要數據獨立的數據表通過ProjectID區分。而一些系統初始化的配置表則可以數據共享。怎么用盡可能少的代碼來管理每個租戶呢?這里提出我個人的思路。

多租戶的實現

第一步:用戶登錄時獲取當前項目,并保存到上下文中。

第二步:通過EntityListeners注解監聽,在實體被創建時將當前項目ID保存到數據庫中。

第三步:通過自定義攔截器,攔截需要數據隔離的sql語句,重新拼接查詢條件。

將當前項目保存到上下文中,不同的安全框架實現的方法也有所不同,實現的方式也多種多樣,這里就不貼出代碼。

通過EntityListeners注解可以對實體屬性變化的跟蹤,它提供了保存前,保存后,更新前,更新后,刪除前,刪除后等狀態,就像是攔截器一樣。這里我們可以用到PrePersist 在保存前將項目ID賦值

  1. @MappedSuperclass 
  2. @EntityListeners(ProjectIdListener::class) 
  3. @Poko 
  4. class TenantModel: AuditModel() { 
  5.     var projectId: String? = null 
  6. class ProjectIdListener { 
  7.  
  8.     @PrePersist 
  9.     fun setProjectId(resultObj: Any) { 
  10.         try { 
  11.             val projectIdProperty = resultObj::class.java.superclass.getDeclaredField("projectId"
  12.             if (projectIdProperty.type == String::class.java) { 
  13.                 projectIdProperty.isAccessible = true 
  14.                 projectIdProperty.set(resultObj, ContextUtils.getCurrentProjectId()) 
  15.             } else { 
  16.             } 
  17.         } catch (ex: Exception) { 
  18.         } 
  19.     } 

自定義SQL攔截器,通過實現StatementInspector接口,實現inspect方法即可。不同的業務邏輯,實現的邏輯也不一樣,這里就不貼代碼了。

注意:

一)、以上是kotlin代碼,IDEA支持Kotlin和Java代碼的互轉。

二)、需要數據隔離的實體,繼承TenantModel類即可,沒有繼承的實體默認為數據共享。

三)、ContextUtils是自定義獲取上下文的工具類。

數據備份

業務分析

到了文章的重點。數據的備份目的是數據遷移和數據的還原。友好的備份格式可以為數據遷移減少很多工作量。剛開始覺得這個需求很簡單,MySQL的數據備份做過很多次,也很簡單。但數據備份不僅僅是數據恢復,還有數據遷移的功能(A項目下的數據備份后,可以導入的B項目下)。這下就有意思了。我們理一理:

一)、數據備份是數據隔離的。A項目數據備份,只能備份A項目下的數據。

二)、備份的數據用于數據恢復。

三)、備份的數據用于數據遷移,之前存在的關聯數據要重新綁定關聯關系。

四)、數據恢復和遷移過程中,注意重復導入和事務問題。

針對上面的分析,一般都有會三種解決思路:

一)、用MySQL自帶的命令導入和導出。

二)、找已經做好的輪子。(如果有,請麻煩告知一下)

三)、自己實現將數據轉為JSON數據,再由JSON數據導入的功能。

因為需求三和需求四的特殊性,MySQL自帶的命令很難滿足,也沒有合適的輪子。只能自己實現,這樣做也更放心點。

實現流程

第一步:確定表的順序。項目之間數據遷移后,需要重新綁定表的關聯關系,優先導入導出沒有外鍵關聯的表。

第二步:遍歷每張表,將數據轉成JSON格式數據一行行寫入到文本文件中。

導出數據偽代碼:

  1. fun exportSystemData(request: HttpServletRequest, response: HttpServletResponse) { 
  2.     // 校驗權限 
  3.     checkAuthority("導出系統數據"
  4.     // 獲取當前項目 
  5.     val currentProjectId = ContextUtils.getCurrentProjectId() 
  6.     val systemFilePath = "${attachmentPath}system${File.separator}$currentProjectId" 
  7.     val file = File(systemFilePath) 
  8.     if (!file.exists()) { 
  9.         file.mkdirs() 
  10.     } 
  11.     // 獲取數據獨立的表名(方便查詢)和類名的全路徑(方便反射) 
  12.     val moreProjectEntityMap = CommonUtils.getMoreProjectEntity() 
  13.     moreProjectEntityMap.remove(CommonUtils.toUnderline(SystemLog::class.simpleName)) 
  14.     moreProjectEntityMap.remove(CommonUtils.toUnderline(AlarmRecord::class.simpleName)) 
  15.     // 生成文件 
  16.     moreProjectEntityMap.forEach { entry -> 
  17.         var tableFile: FileWriter? = null 
  18.         try { 
  19.             tableFile = FileWriter(File(systemFilePath, "${entry.key}.txt")) 
  20.             dataManagementService.findAll(Class.forName(entry.value)).forEach { 
  21.                 tableFile.write("${JSONObject.toJSONString(it)} \n"
  22.             } 
  23.         } catch (e: Exception) { 
  24.             e.printStackTrace() 
  25.         } finally { 
  26.             tableFile?.let { 
  27.                 it.flush() 
  28.                 it.close() 
  29.             } 
  30.         } 
  31.     } 
  32.     // 壓縮成一個文件 
  33.     fileUtil.zip(systemFilePath) 
  34.     file.listFiles().forEach { it.delete() } 
  35.     fileUtil.downloadAttachment("$systemFilePath.zip", response) 

數據遷移

業務分析

備份后的數據有兩個用途。第一是數據還原;最重要的是數據遷移。將A項目中的配置導入到B項目中,可以提高用戶的效率。數據還原最簡單,這里重點介紹數據遷移的思路(可能不太合理)

數據遷移最麻煩的就是新創建后的數據如何重新綁定主外表的關系。其次就是如果導入過程中失敗,事務的處理問題。為了處理這兩個問題,我選擇新增一張表維護新舊ID的遷移記錄。每次導入成功后就在表中保存數據。這樣可以避免重復導入的情況。也為新數據重新綁定主外關系做準備。

實現步驟

第一步:解壓上傳后的文件,并按照指定的排序順序讀取解壓后的文件。

第二步:一行行讀取數據,通過反射將JSON格式字符串轉為對象。遍歷對象的值將舊ID根據數據遷移記錄替換成遷移后的新ID。

第三步:檢擦數據遷移記錄表中是否已經存在遷移記錄,若沒有則插入數據并記錄日志。

第四步:若數據遷移記錄表中已經存在記錄,則更新數據。

第五步:讀取第二行數據,重復執行。

數據恢復偽代碼

  1. fun importSystemData(file: MultipartFile, request: HttpServletRequest) { 
  2.     checkAuthority("導入系統數據"
  3.     val currentProjectId = ContextUtils.getCurrentProjectId() 
  4.     val systemFilePath = "${attachmentPath}system" 
  5.     val tempFile = File(systemFilePath, file.originalFilename) 
  6.     val fileOutputStream = FileOutputStream(tempFile) 
  7.     fileOutputStream.write(file.bytes) 
  8.     fileOutputStream.close() 
  9.     // 獲取排序后遷移表 
  10.     val moreProjectEntityMap = CommonUtils.getMoreProjectEntity() 
  11.     moreProjectEntityMap.remove(CommonUtils.toUnderline(SystemLog::class.simpleName)) 
  12.     val files: MutableMap<String, File> = mutableMapOf() 
  13.     fileUtil.unzip(tempFile.absoluteFile, systemFilePath, "").forEach { 
  14.         files[it!!.nameWithoutExtension] = it 
  15.     } 
  16.     val dataTransferHistories = dataTransferHistoryRepository.findByProjectId(currentProjectId).toMutableList() 
  17.     try { 
  18.         moreProjectEntityMap.keys.forEach {  fileName -> 
  19.             val tableFile = files.getOrDefault(fileName, null) ?: return@forEach 
  20.             val entity = Class.forName(moreProjectEntityMap[fileName]) 
  21.             tableFile.forEachLine { dataStr -> 
  22.                 val data = JSONObject.parseObject(dataStr, entity) 
  23. //              獲取對象所有屬性 
  24.                 val fieldMap = CommonUtils.getEntityAllField(data) 
  25. //              獲取數據遷移的舊ID 
  26.                 val id = fieldMap["id"]!!.get(data) as String 
  27.                 val dataTransferHistory = dataTransferHistories.find { it.oldId == id } 
  28. //              重新綁定遷移數據后的id 
  29.                 handleEntityData(data, fieldMap, moreProjectEntityMap.values.toList(), dataTransferHistories) 
  30.                 fieldMap["projectId"]!!.set(data, currentProjectId) 
  31.                 if (null == dataTransferHistory || null == dataManagementService.getByIdElseNull(dataTransferHistory.newId, entity)) { 
  32.                     val saved = dataManagementService.create(data, entity) 
  33. //                  綁定舊ID和新ID的關系 
  34.                     val savedId = CommonUtils.getEntityAllField(saved)["id"]!!.get(saved) as String 
  35.                     if (null == dataTransferHistory) { 
  36.                         dataTransferHistories.add(DataTransferHistory(id, savedId, currentProjectId, fileName)) 
  37.                     } 
  38.                 } else { 
  39.                     fieldMap["id"]!!.set(data, dataTransferHistory.newId) 
  40.                     dataManagementService.update(data, entity) 
  41.                 } 
  42.             } 
  43.         } 
  44.     } catch (e: Exception) { 
  45.         e.printStackTrace() 
  46.         throw IllegalArgumentException("數據導入失敗"
  47.     } finally { 
  48.         tempFile.delete() 
  49.         files.values.forEach { it.delete() } 
  50.         recordDataTransferHistory(dataTransferHistories) 
  51.     } 
  52.  
  53. // 記錄數據遷移 
  54. private fun recordDataTransferHistory(dataTransferHistories: MutableList<DataTransferHistory>) { 
  55.     dataTransferHistoryRepository.saveAll(dataTransferHistories) 
  56.  
  57. // 重新綁定主外關系表 
  58. fun handleEntityData(sourceClass: Any, fieldMap: MutableMap<String, Field>, classPaths: List<String>, dataTransferHistories: MutableList<DataTransferHistory>) { 
  59.     val currentProjectId = ContextUtils.getCurrentProjectId() 
  60.     fieldMap.values.forEach { field -> 
  61.         val classPath = field.type.toString().split(" ").last() 
  62.         // 一對多或多對多關系 
  63.         if (classPath == "java.util.List") { 
  64.             val listValue = field.get(sourceClass) as List<*> 
  65.             listValue.forEach { listObj -> 
  66.                 listObj?.let { changeOldRelId4NewData(it, dataTransferHistories, currentProjectId) } 
  67.             } 
  68.         } 
  69.         // 一對一或多對一關系 
  70.         if (classPaths.contains(classPath)) { 
  71.             val value = field.get(sourceClass)?: return@forEach 
  72.             changeOldRelId4NewData(value, dataTransferHistories, currentProjectId) 
  73.         } 
  74.         // 字符串ID關聯 
  75.         if (classPath == "java.lang.String" && null != field.get(sourceClass)) { 
  76.             var oldId = field.get(sourceClass).toString() 
  77.             dataTransferHistories.forEach { 
  78.                 oldId = oldId.replace(it.oldId, it.newId) 
  79.             } 
  80.             field.set(sourceClass, oldId) 
  81.         } 
  82.     } 
  83.  
  84. fun changeOldRelId4NewData(data: Any, dataTransferHistories: MutableList<DataTransferHistory>, currentProjectId: String) { 
  85.     val fieldMap = CommonUtils.getEntityAllField(data) 
  86.     fieldMap.values.forEach { field -> 
  87.         if (field.type.toString().contains("java.lang.String") && null != field.get(data)) { 
  88.             var oldId = field.get(data).toString() 
  89.             dataTransferHistories.forEach { 
  90.                 oldId = oldId.replace(it.oldId, it.newId) 
  91.             } 
  92.             field.set(data, oldId) 
  93.         } 
  94.     } 
  95.     fieldMap["projectId"]!!.set(data, currentProjectId) 
  96. /** 
  97.  * 數據遷移記錄表 
  98.  */ 
  99. @Entity 
  100. @Table(uniqueConstraints = [UniqueConstraint(columnNames = ["oldId""projectId"])]) 
  101. data class DataTransferHistory ( 
  102.  
  103.         var oldId: String = ""
  104.         var newId: String = ""
  105.         var projectId: String = ""
  106.         var tableName: String = ""
  107.         var createTime: Instant = Instant.now(), 
  108.         @Id 
  109.         @GenericGenerator(name = "idGenerator", strategy = "uuid"
  110.         @GeneratedValue(generator = "idGenerator"
  111.         var id: String = "" 
  112.  

到這里就結束了,以上思路僅供參考。

小結

一)、數據備份需要項目獨立

二)、通過項目ID 區分備份的數據是用來數據還原還是數據遷移

三)、數據遷移過程中需要考慮數據重復導入的問題

四)、數據遷移過程中需要重新綁定主外鍵的關聯

五)、第三和第四點可以通過記錄數據遷移表做輔助

六)、數據遷移過程盡量避免刪除操作。避免對其他項目造成影響。

責任編輯:武曉燕 來源: Segmentfault
相關推薦

2015-08-12 15:46:02

SaaS多租戶數據存儲

2015-04-02 11:04:27

云應用SaaSOFBIZ

2011-03-31 12:17:07

Cacti備份

2017-10-23 21:19:10

數據中心SDN軟件定義網絡

2024-04-02 09:01:45

2023-11-06 08:26:11

Spring微服務架構

2011-10-21 12:29:38

IPv6雙協議DNS

2013-11-26 17:29:43

思科呼叫中心多租戶

2019-10-25 14:17:00

邊緣計算數據中心多租戶數據中心

2023-12-14 12:26:16

SaaS數據庫方案

2020-10-16 08:57:51

云平臺之多租戶的實踐

2020-09-15 07:00:00

SaaS架構架構

2013-04-15 09:52:13

程序員

2022-02-23 08:55:06

數據遷移分庫分表數據庫

2022-05-13 07:26:28

策略模式設計模式

2021-03-17 08:11:21

SQL工作日數據

2022-01-12 17:39:16

Spring多租戶數據

2023-06-07 13:50:00

SaaS多租戶系統

2020-07-30 09:44:26

數據中心IT技術

2010-05-21 12:52:55

點贊
收藏

51CTO技術棧公眾號

国产精品一区二区免费不卡| 九一成人免费视频| 亚洲综合一区二区精品导航| av资源一区二区| www.天天色| 奇米亚洲欧美| 日韩一区二区三区在线视频| 国产原创popny丨九色| 国产一区二区三区不卡在线| 久久成人久久鬼色| 欧美与欧洲交xxxx免费观看| 五月天免费网站| 福利欧美精品在线| 欧美日韩另类一区| 欧美日韩成人免费视频| 在线国产91| 91亚洲精品久久久蜜桃| 成人欧美在线观看| 国产成人无码一区二区在线播放| 天天做天天爱综合| 亚洲精品美女在线| 永久免费看片在线观看| abab456成人免费网址| 亚洲午夜免费电影| 欧美精品二区三区四区免费看视频 | 国产aⅴ综合色| 国产精品美女www爽爽爽视频| 久久久久久久久久99| 成人免费a**址| 亚洲国产日韩欧美在线99| 99日在线视频| av成人在线播放| 欧美午夜精品久久久久久浪潮 | 欧美私人网站| 久久久.com| 国产一区二区三区高清视频| 国产特黄一级片| 美腿丝袜亚洲综合| 国产精品99久久久久久久久| 日韩三级免费看| 欧美a级在线| 日韩视频免费在线| 丁香激情五月少妇| 中日韩免视频上线全都免费| 亚洲国产中文字幕在线观看| 性生交大片免费看l| 欧美男女视频| 欧美日韩日本视频| 天天色综合社区| 992tv国产精品成人影院| 欧美日韩国产综合视频在线观看中文 | 婷婷中文字幕在线观看| 亚州一区二区三区| 色先锋资源久久综合| 久久国产成人精品国产成人亚洲 | 日本精品久久中文字幕佐佐木| 日本免费在线播放| 亚洲电影av| 91精品国产高清| 久久国产精品免费看| 国产精品久久久久久久久久妞妞| 国语自产精品视频在线看一大j8| 国产一级大片在线观看| 欧美三级网页| 久久免费视频网| 日本高清www免费视频| 99热免费精品在线观看| 97avcom| 久久99精品波多结衣一区| 国产欧美日本| 日韩免费观看网站| 成人黄色片在线观看| 蜜桃视频一区二区三区在线观看| 国产精品视频永久免费播放| 亚洲天堂视频在线| 国产麻豆成人传媒免费观看| 福利视频一区二区三区| 香蕉视频免费看| 国产婷婷一区二区| 中文字幕久精品免| 美足av综合网| 日韩欧美一区视频| 91极品视频在线观看| 九九九九九九精品任你躁| 精品国产免费久久| 中国美女乱淫免费看视频| 国产一区网站| 九九精品视频在线| 国产视频91在线| 男女激情视频一区| 99久久精品免费看国产四区| 天堂成人在线| 中文字幕一区二区三区在线观看| 国产美女永久无遮挡| 午夜伦理福利在线| 欧美午夜精品一区| 国产精品成人免费一区久久羞羞| 女厕嘘嘘一区二区在线播放 | 天堂av中文在线| 欧美日韩午夜激情| 日本一二区免费| 久久久免费毛片| 日韩专区在线播放| 日韩人妻无码一区二区三区99| 麻豆成人av在线| 国产一区二区三区高清视频| 麻豆传媒在线观看| 欧美性猛交xxxx黑人| 九九九九九九九九| 一个色免费成人影院| 久久国产精彩视频| 无码人妻av免费一区二区三区| 国产美女主播视频一区| 你懂的视频在线一区二区| 成年人黄视频在线观看| 色综合色综合色综合| www.日本久久| 国内精品久久久久久99蜜桃| 久久久久女教师免费一区| 精品少妇人妻av免费久久洗澡| 成人软件在线观看| 精品久久五月天| 日韩黄色中文字幕| 国产九九精品| 国产91aaa| 免费超碰在线| 欧美图区在线视频| 中文字幕5566| 在线视频观看日韩| 91精品天堂| 免费超碰在线| 欧美日韩精品综合在线| aa一级黄色片| 亚洲精品免费观看| av成人在线电影| 顶级网黄在线播放| 欧美日韩视频第一区| 91激情视频在线| 久久影视三级福利片| 欧美激情videoshd| 国产又粗又猛又爽又黄的视频一 | 国内外成人免费视频| av网站在线免费看推荐| 欧美久久久久中文字幕| 麻豆视频免费在线播放| 男人操女人的视频在线观看欧美| 日韩av高清| jizz日韩| 91成人国产精品| 在线观看日本中文字幕| 欧美中文日韩| 日本免费高清一区二区| 日韩av中字| 国产亚洲视频中文字幕视频| 五月婷婷激情视频| 国产视频在线观看一区二区三区| 中文字幕乱码人妻综合二区三区| 中文有码一区| 国产精品久久久久久亚洲调教| 国产视频二区在线观看| 欧美性猛交xxxxxx富婆| 国产黄色片在线| 久久99精品国产.久久久久久| 伊人av成人| 欧美视频二区欧美影视| 欧美高清无遮挡| 人妻va精品va欧美va| 欧美日韩一区二区免费在线观看| 国产精品揄拍100视频| 玖玖视频精品| 制服国产精品| 白白在线精品| 青青草精品毛片| 91在线不卡| 日韩午夜激情av| 免费观看成人毛片| 中文字幕 久热精品 视频在线| 91精品999| 尤物精品在线| 日本一区视频在线| 久久久久九九精品影院| 久久久久久久一| 国产精品视频二区三区| 欧美精品在线观看一区二区| 国产性生活网站| 国产色一区二区| 日本中文字幕在线不卡| 一本久久知道综合久久| 亚洲综合首页| 国产精东传媒成人av电影| 国产91在线播放九色快色| 久久久久久久久免费视频| 欧美精品一区二| 亚洲国产无线乱码在线观看| 一区二区三区在线观看视频| 成人免费无遮挡无码黄漫视频| 精品综合久久久久久8888| 国产69精品久久久久999小说| 久久综合影院| 成人一区二区在线| 日产精品一区| 久久久久久久久久婷婷| √天堂资源地址在线官网| 精品久久免费看| 亚洲天堂视频网| 欧美色videos| 爱爱视频免费在线观看| 久久久久久久网| 欧美一级大片免费看| 日韩一区欧美二区| www精品久久| 欧美成人milf| 日韩精品国内| 精品国产一区二区三区不卡蜜臂| 国产精品视频久久久| 欧美调教sm| 欧美黑人巨大xxx极品| 国产私拍精品| 日韩精品在线观| 亚洲精品一区二区口爆| 欧美日韩视频在线第一区| 一级做a爰片久久毛片| 亚洲午夜免费视频| 劲爆欧美第一页| 国产精品伦一区| b站大片免费直播| 99re8在线精品视频免费播放| 欧美日韩一区二区区别是什么| 久久99最新地址| 国产嫩草在线观看| 久久永久免费| 国产免费毛卡片| 一本久久综合| 日韩激情免费视频| 影音先锋中文字幕一区二区| 日韩精品一区二区免费| 欧美freesex交免费视频| www亚洲国产| 五月天综合网站| 亚洲精品一区二区三区樱花| 国产一区二区三区站长工具| 免费亚洲一区二区| 欧美一区二区三区久久| 久久精品日产第一区二区三区乱码| 在线精品国产亚洲| 成人免费视频观看视频| 亚洲电影一区| 国产精品日韩一区二区三区 | 日韩三级av在线播放| 国产老妇伦国产熟女老妇视频| 欧美日韩高清在线| 一区二区三区精| 欧美日韩在线观看一区二区| 亚洲视屏在线观看| 欧美老年两性高潮| 国产原创中文av| 337p亚洲精品色噜噜狠狠| 国产免费高清视频| 日韩一区二区在线看片| www香蕉视频| 亚洲国产日韩欧美综合久久| 天天干天天爽天天操| 亚洲人在线视频| 国产69久久| 精品国产视频在线 | 97婷婷涩涩精品一区| 热三久草你在线| 日本中文字幕久久看| 精品视频一区二区三区四区五区| caoporn国产一区二区| 欧美精品久久| 日韩av久操| www国产免费| 亚洲激情一区| 国产福利影院在线观看| 经典一区二区三区| 野战少妇38p| 久久久久国色av免费看影院| 91麻豆精品久久毛片一级| 亚洲精品日产精品乱码不卡| 日本一级淫片免费放| 日韩欧美在线免费| 91资源在线视频| 精品91自产拍在线观看一区| 国产综合在线观看| 久久精品亚洲一区| 成年男女免费视频网站不卡| 国产精品久久久久久久av电影| 久久九九精品视频| 日本日本精品二区免费| 亚洲欧美综合| 一区二区在线播放视频| 国产精品99久久久| 美女久久久久久久久久| 亚洲精品美国一| 在线免费观看av网址| 日韩欧美电影一区| 黄色小视频在线免费观看| 亚洲天堂男人天堂| 色呦呦网站在线观看| 国产精品va在线播放| 2023国产精华国产精品| 五月天亚洲综合| 夜夜嗨一区二区三区| 奇米777在线视频| 国产亚洲成av人在线观看导航| 精品99久久久久成人网站免费| 日本精品一级二级| 好吊视频一区二区三区| 在线视频日韩精品| 日韩伦理在线一区| 99国产盗摄| 清纯唯美综合亚洲| aa在线免费观看| 国产·精品毛片| а天堂中文在线资源| 色综合久久久久| 亚洲精品国产av| 麻豆一区二区在线观看| 深夜视频一区二区| 欧美日本韩国在线| 亚洲国产mv| 丰满少妇中文字幕| 国产精品久久三区| 夜夜爽妓女8888视频免费观看| 亚洲国产成人精品久久| 综合久久2019| 91久久精品国产91久久性色| 免费观看不卡av| 国产午夜大地久久| 国产69精品久久99不卡| 成人观看免费视频| 91精品婷婷国产综合久久| 在线看免费av| 国产精品久久久久久久久久久久久 | av福利在线播放| 国产精品黄色av| 久久av免费| 无码内射中文字幕岛国片| 久久综合九色综合欧美98 | 在线观看视频欧美| 欧美孕妇性xxxⅹ精品hd| **欧美日韩vr在线| 欧美亚洲大陆| 欧美日韩亚洲第一| 91丨九色丨尤物| 亚洲综合图片网| 在线观看国产精品91| 中文字幕日本一区二区| 日韩av电影免费观看| 人人超碰91尤物精品国产| 91成人在线免费视频| 在线免费观看一区| av在线播放网站| 国产精品一区二区在线| 久久亚洲精品中文字幕蜜潮电影| 超碰超碰在线观看| 国产精品久线在线观看| 97人妻人人澡人人爽人人精品| 久久视频免费观看| 日韩免费成人| 日韩欧美精品免费| 91网站视频在线观看| 波多野结衣激情视频| 少妇高潮久久77777| 9999精品视频| 福利视频免费在线观看| 99久久99久久免费精品蜜臀| 性无码专区无码| 一区三区二区视频| 99热这里有精品| 无颜之月在线看| av不卡一区二区三区| 日批视频免费在线观看| 最近2019年好看中文字幕视频 | caoporn免费在线| 成人h视频在线观看| 夜夜精品视频| 成人信息集中地| 精品女同一区二区| 男人皇宫亚洲男人2020| 伊人久久婷婷色综合98网| 国产成人av自拍| 毛片毛片女人毛片毛片| 久久精品久久久久久| 国产精品chinese在线观看| 日日鲁鲁鲁夜夜爽爽狠狠视频97 | 精品一区二区免费看| 免费一级黄色大片| 亚洲精品综合精品自拍| 亚洲欧美在线人成swag| 青青草成人免费在线视频| 亚洲国产岛国毛片在线| 亚洲国产精品成人久久蜜臀| 国产成人一区二区三区电影| 2023国产精品久久久精品双| 久久性爱视频网站| 欧美视频在线一区| 大桥未久在线视频| 亚洲第一页在线视频|