亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發(fā) > Java > 正文

通過反射注解批量插入數(shù)據(jù)到DB的實(shí)現(xiàn)方法

2024-07-14 08:43:31
字體:
供稿:網(wǎng)友

批量導(dǎo)入思路

最近遇到一個(gè)需要批量導(dǎo)入數(shù)據(jù)問題。后來考慮運(yùn)用反射做成一個(gè)工具類,思路是首先定義注解接口,在bean類上加注解,運(yùn)行時(shí)通過反射獲取傳入Bean的注解,自動(dòng)生成需要插入DB的SQL,根據(jù)設(shè)置的參數(shù)值批量提交。不需要寫具體的SQL,也沒有DAO的實(shí)現(xiàn),這樣一來批量導(dǎo)入的實(shí)現(xiàn)就和具體的數(shù)據(jù)庫表徹底解耦。實(shí)際批量執(zhí)行的SQL如下:

insert into company_candidate(company_id,user_id,card_id,facebook_id,type,create_time,weight,score) VALUES (?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE type=?,weight=?,score=?

第一步,定義注解接口

注解接口Table中定義了數(shù)據(jù)庫名和表名。RetentionPolicy.RUNTIME表示該注解保存到運(yùn)行時(shí),因?yàn)槲覀冃枰谶\(yùn)行時(shí),去讀取注解參數(shù)來生成具體的SQL。

@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface Table {  /**   * 表名   * @return   */  String tableName() default "";  /**   * 數(shù)據(jù)庫名稱   * @return   */  String dbName();}

注解接口TableField中定義了數(shù)據(jù)庫表名的各個(gè)具體字段名稱,以及該字段是否忽略(忽略的話就會以數(shù)據(jù)庫表定義默認(rèn)值填充,DB非null字段的注解不允許出現(xiàn)把ignore注解設(shè)置為true)。update注解是在主鍵在DB重復(fù)時(shí),需要更新的字段。

@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface TableField {  /**   * 對應(yīng)數(shù)據(jù)庫字段名稱   * @return   */  String fieldName() default "";  /**   * 是否是主鍵   * @return   */  boolean pk() default false;  /**   * 是否忽略該字段   * @return   */  boolean ignore() default false;  /**   * 當(dāng)數(shù)據(jù)存在時(shí),是否更新該字段   * @return   */  boolean update() default false;}

第二步,給Bean添加注解

給Bean添加注解(為了簡潔省略了import和set/get方法以及其他屬性),@TableField(fieldName = "company_id")表示companyId字段對應(yīng)DB表的字段名為"company_id",其中updateTime屬性的注解含有ignore=true,表示該屬性值會被忽略。另外serialVersionUID屬性由于沒有@TableField注解,在更新DB時(shí)也會被忽略。

代碼如下:

@Table(dbName = "company", tableName = "company_candidate")public class CompanyCandidateModel implements Serializable{ private static final long serialVersionUID = -1234554321773322135L; @TableField(fieldName = "company_id") private int companyId; @TableField(fieldName = "user_id") private int userId; //名片id @TableField(fieldName = "card_id") private int cardId; //facebookId @TableField(fieldName = "facebook_id") private long facebookId;  @TableField(fieldName="type", update = true) private int type; @TableField(fieldName = "create_time") private Date createTime; @TableField(fieldName = "update_time", ignore=true) private Date updateTime; // 權(quán)重  @TableField(fieldName="weight", update = true) private int weight; // 分值  @TableField(fieldName="score", update = true) private double score;

第三步,讀取注解的反射工具類

讀取第二步Bean類的注解的反射工具類。利用反射getAnnotation(TableField.class)讀取注解信息,為批量SQL的拼接最好準(zhǔn)備。

getTableBeanFieldMap()方法里生成一個(gè)LinkedHashMap對象,是為了保證生成插入SQL的field順序,之后也能按同樣的順序給參數(shù)賦值,避免錯(cuò)位。getSqlParamFields()方法也類似,是為了給PreparedStatement設(shè)置參數(shù)用。

代碼如下:

public class ReflectUtil {  /**   * <Class,<表定義Field名,Bean定義Field>>的map緩存   */  private static final Map<Class<?>, Map<string field="">> classTableBeanFieldMap = new HashMap<Class<?>, Map<string field="">>();  // 用來按順序填充SQL參數(shù),其中存儲的Field和classTableBeanFieldMap保存同樣的順序,但數(shù)量多出ON DUPLICATE KEY UPDATE部分Field  private static final Map<Class<?>, List<field>> sqlParamFieldsMap = new HashMap<Class<?>, List<field>>();   private ReflectUtil(){};  /**   * 獲取該類上所有@TableField注解,且沒有忽略的字段的Map。   * <br />返回一個(gè)有序的LinkedHashMap類型   * <br />其中key為DB表中的字段,value為Bean類里的屬性Field對象   * @param clazz   * @return   */  public static Map<string field=""> getTableBeanFieldMap(Class<?> clazz) {   // 從緩存獲取   Map<string field=""> fieldsMap = classTableBeanFieldMap.get(clazz);   if (fieldsMap == null) {   fieldsMap = new LinkedHashMap<string field="">();      for (Field field : clazz.getDeclaredFields()) {// 獲得所有聲明屬性數(shù)組的一個(gè)拷貝       TableField annotation = field.getAnnotation(TableField.class);        if (annotation != null && !annotation.ignore() && !"".equals(annotation.fieldName())) {          field.setAccessible(true);// 方便后續(xù)獲取私有域的值         fieldsMap.put(annotation.fieldName(), field);        }  }      // 放入緩存      classTableBeanFieldMap.put(clazz, fieldsMap);   }   return fieldsMap;  }  /**   * 獲取該類上所有@TableField注解,且沒有忽略的字段的Map。ON DUPLICATE KEY UPDATE后需要更新的字段追加在list最后,為了填充參數(shù)值準(zhǔn)備   * <br />返回一個(gè)有序的ArrayList類型   * <br />其中key為DB表中的字段,value為Bean類里的屬性Field對象   * @param clazz   * @return   */  public static List<field> getSqlParamFields(Class<?> clazz) {   // 從緩存獲取   List<field> sqlParamFields = sqlParamFieldsMap.get(clazz);   if (sqlParamFields == null) {   // 獲取所有參數(shù)字段     Map<string field=""> fieldsMap = getTableBeanFieldMap(clazz);   sqlParamFields = new ArrayList<field>(fieldsMap.size() * 2);     // SQL后段ON DUPLICATE KEY UPDATE需要更新的字段     List<field> updateParamFields = new ArrayList<field>();   Iterator<Entry<string field="">> iter = fieldsMap.entrySet().iterator();   while (iter.hasNext()) {    Entry<string field=""> entry = (Entry<string field="">) iter.next();    Field field = entry.getValue();    // insert語句對應(yīng)sql參數(shù)字段    sqlParamFields.add(field);        // ON DUPLICATE KEY UPDATE后面語句對應(yīng)sql參數(shù)字段        TableField annotation = field.getAnnotation(TableField.class);    if (annotation != null && !annotation.ignore() && annotation.update()) {    updateParamFields.add(field);    }   }   sqlParamFields.addAll(updateParamFields);      // 放入緩存   sqlParamFieldsMap.put(clazz, sqlParamFields);   }   return sqlParamFields;  }  /**   * 獲取表名,對象中使用@Table的tableName來標(biāo)記對應(yīng)數(shù)據(jù)庫的表名,若未標(biāo)記則自動(dòng)將類名轉(zhuǎn)成小寫   *    * @param clazz   * @return   */  public static String getTableName(Class<?> clazz) {    Table table = clazz.getAnnotation(Table.class);    if (table != null && table.tableName() != null && !"".equals(table.tableName())) {      return table.tableName();    }    // 當(dāng)未配置@Table的tableName,自動(dòng)將類名轉(zhuǎn)成小寫    return clazz.getSimpleName().toLowerCase();  }  /**   * 獲取數(shù)據(jù)庫名,對象中使用@Table的dbName來標(biāo)記對應(yīng)數(shù)據(jù)庫名   * @param clazz   * @return   */  public static String getDBName(Class<?> clazz) {    Table table = clazz.getAnnotation(Table.class);    if (table != null && table.dbName() != null) {      // 注解@Table的dbName      return table.dbName();    }    return "";  }

第四步,生成SQL語句

根據(jù)上一步的方法,生成真正執(zhí)行的SQL語句。

insert into company_candidate(company_id,user_id,card_id,facebook_id,type,create_time,weight,score) VALUES (?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE type=?,weight=?,score=?

代碼如下:

public class SQLUtil {  private static final char COMMA = ',';  private static final char BRACKETS_BEGIN = '(';  private static final char BRACKETS_END = ')';  private static final char QUESTION_MARK = '?';  private static final char EQUAL_SIGN = '=';  private static final String INSERT_BEGIN = "INSERT INTO ";  private static final String INSERT_VALURS = " VALUES ";  private static final String DUPLICATE_UPDATE = " ON DUPLICATE KEY UPDATE ";  // 數(shù)據(jù)庫表名和對應(yīng)insertupdateSQL的緩存  private static final Map<string string=""> tableInsertSqlMap = new HashMap<string string="">();  /**   * 獲取插入的sql語句,對象中使用@TableField的fieldName來標(biāo)記對應(yīng)數(shù)據(jù)庫的列名,若未標(biāo)記則忽略   * 必須標(biāo)記@TableField(fieldName = "company_id")注解   * @param tableName   * @param fieldsMap   * @return   * @throws Exception   */  public static String getInsertSql(String tableName, Map<string field=""> fieldsMap) throws Exception {   String sql = tableInsertSqlMap.get(tableName);   if (sql == null) {   StringBuilder sbSql = new StringBuilder(300).append(INSERT_BEGIN);   StringBuilder sbValue = new StringBuilder(INSERT_VALURS);   StringBuilder sbUpdate = new StringBuilder(100).append(DUPLICATE_UPDATE);   sbSql.append(tableName);   sbSql.append(BRACKETS_BEGIN);   sbValue.append(BRACKETS_BEGIN);   Iterator<Entry<string field="">> iter = fieldsMap.entrySet().iterator();   while (iter.hasNext()) {    Entry<string field=""> entry = (Entry<string field="">) iter.next();    String tableFieldName = entry.getKey();    Field field = entry.getValue();    sbSql.append(tableFieldName);    sbSql.append(COMMA);    sbValue.append(QUESTION_MARK);    sbValue.append(COMMA);    TableField tableField = field.getAnnotation(TableField.class);    if (tableField != null && tableField.update()) {    sbUpdate.append(tableFieldName);    sbUpdate.append(EQUAL_SIGN);    sbUpdate.append(QUESTION_MARK);    sbUpdate.append(COMMA);    }   }   // 去掉最后的逗號   sbSql.deleteCharAt(sbSql.length() - 1);   sbValue.deleteCharAt(sbValue.length() - 1);   sbSql.append(BRACKETS_END);   sbValue.append(BRACKETS_END);   sbSql.append(sbValue);   if (!sbUpdate.toString().equals(DUPLICATE_UPDATE)) {    sbUpdate.deleteCharAt(sbUpdate.length() - 1);    sbSql.append(sbUpdate);   }   sql = sbSql.toString();   tableInsertSqlMap.put(tableName, sql);   }    return sql;  }

第五步,批量SQL插入實(shí)現(xiàn)

從連接池獲取Connection,SQLUtil.getInsertSql()獲取執(zhí)行的SQL語句,根據(jù)sqlParamFields來為PreparedStatement填充參數(shù)值。當(dāng)循環(huán)的值集合到達(dá)batchNum時(shí)就提交一次。

代碼如下:

  /**   * 批量插入,如果主鍵一致則更新。結(jié)果返回更新記錄條數(shù)<br />   * @param dataList   *      要插入的對象List   * @param batchNum   *      每次批量插入條數(shù)   * @return 更新記錄條數(shù)   */  public int batchInsertSQL(List<? extends Object> dataList, int batchNum) throws Exception {   if (dataList == null || dataList.isEmpty()) {   return 0;   }    Class<?> clazz = dataList.get(0).getClass();    String tableName = ReflectUtil.getTableName(clazz);    String dbName = ReflectUtil.getDBName(clazz);    Connection connnection = null;    PreparedStatement preparedStatement = null;    // 獲取所有需要更新到DB的屬性域    Map<string field=""> fieldsMap = ReflectUtil.getTableBeanFieldMap(dataList.get(0).getClass());    // 根據(jù)需要插入更新的字段生成SQL語句    String sql = SQLUtil.getInsertSql(tableName, fieldsMap);    log.debug("prepare to start batch operation , sql = " + sql + " , dbName = " + dbName);    // 獲取和SQL語句同樣順序的填充參數(shù)Fields    List<field> sqlParamFields = ReflectUtil.getSqlParamFields(dataList.get(0).getClass());    // 最終更新結(jié)果條數(shù)    int result = 0;    int parameterIndex = 1;// SQL填充參數(shù)開始位置為1    // 執(zhí)行錯(cuò)誤的對象    List<object> errorsRecords = new ArrayList</object><object>(batchNum);//指定數(shù)組大小    // 計(jì)數(shù)器,batchNum提交后內(nèi)循環(huán)累計(jì)次數(shù)    int innerCount = 0;    try {      connnection = this.getConnection(dbName);      // 設(shè)置非自動(dòng)提交      connnection.setAutoCommit(false);      preparedStatement = connnection.prepareStatement(sql);      // 當(dāng)前操作的對象      Object object = null;      int totalRecordCount = dataList.size();      for (int current = 0; current < totalRecordCount; current++) {        innerCount++;        object = dataList.get(current);       parameterIndex = 1;// 開始參數(shù)位置為1       for(Field field : sqlParamFields) {       // 放入insert語句對應(yīng)sql參數(shù)          preparedStatement.setObject(parameterIndex++, field.get(object));       }       errorsRecords.add(object);        preparedStatement.addBatch();        // 達(dá)到批量次數(shù)就提交一次        if (innerCount >= batchNum || current >= totalRecordCount - 1) {          // 執(zhí)行batch操作          preparedStatement.executeBatch();          preparedStatement.clearBatch();          // 提交          connnection.commit();          // 記錄提交成功條數(shù)          result += innerCount;          innerCount = 0;          errorsRecords.clear();        }        // 盡早讓GC回收        dataList.set(current, null);      }      return result;    } catch (Exception e) {      // 失敗后處理方法      CallBackImpl.getInstance().exectuer(sql, errorsRecords, e);      BatchDBException be = new BatchDBException("batch run error , dbName = " + dbName + " sql = " + sql, e);      be.initCause(e);      throw be;    } finally {      // 關(guān)閉      if (preparedStatement != null) {       preparedStatement.clearBatch();        preparedStatement.close();      }      if (connnection != null)        connnection.close();    }  }

最后,批量工具類使用例子

在mysql下的開發(fā)環(huán)境下測試,5萬條數(shù)據(jù)大概13秒。

List<companycandidatemodel> updateDataList = new ArrayList<companycandidatemodel>(50000);// ...為updateDataList填充數(shù)據(jù)int result = batchJdbcTemplate.batchInsertSQL(updateDataList, 50);

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對VeVb武林網(wǎng)的支持。


注:相關(guān)教程知識閱讀請移步到JAVA教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
欧美亚洲国产成人| 免费一级全黄少妇性色生活片| 日韩黄色免费观看| 欧美黑人狂野猛交老妇| 一级片久久久久| 亚洲精品国产一区二区三区四区在线| 免费成人在线电影| 伊人av成人| 国产黄色在线播放| 在线观看三级网站| 欧美天堂影院| 涩涩视频在线免费看| 91精品国产欧美一区二区成人| 91在线资源站| 久草亚洲一区| 中文字幕人妻熟女人妻洋洋| 91亚洲一区二区| 成人免费福利| 国产精品美女久久久久av超清| 久久久久久久久久久91| 先锋影音av网站| 东京干手机福利视频| 国产精品高清免费在线观看| 国产精品成人aaaa在线| 国产黄色在线播放| av在线不卡顿| 欧美韩日一区二区三区| 欧美二区三区的天堂| h网站在线观看| 国色天香一二三期区别大象| 中文字幕色婷婷在线视频| 国产精品va在线播放| 国产啊啊啊视频在线观看| 欧美精品久久久久久久久46p| 一区二区三区免费在线视频| aa视频在线观看| 国产无一区二区| 99久久99久久精品免费看小说.| 欧美成人国产va精品日本一级| 女~淫辱の触手3d动漫| 网友自拍区视频精品| 天天摸天天碰天天添| 亚洲午夜三级在线| 精品久久网站| 欧美一级片免费| 色青青草原桃花久久综合| 精品国产乱码久久久久酒店| 青青草原在线免费观看视频| 亚洲国产成人精品视频| 内射一区二区三区| 91美女高潮出水| 又色又爽又黄无遮挡的免费视频| 亚洲va韩国va欧美va| 国产欧美va欧美va香蕉在线| 欧美在线制服丝袜| 美女的奶胸大爽爽大片| 99国产欧美久久久精品| 奇米成人av国产一区二区三区| 精品国产一区二区三区不卡| 3d动漫精品啪啪1区2区免费| 亚洲日本一区二区| 亚洲综合男人的天堂| 亚洲精品久久| 99视频精品在线| 韩国三级中文字幕hd久久精品| 动漫精品一区二区| 亚洲国产精品一区| 欧美午夜精品免费| 亚洲综合国产| av高清在线| 国产成人在线综合| 五月婷婷丁香色| 中文字幕电影在线观看| 日本综合一区二区三区| 人妻偷人精品一区二区三区| 欧美日韩综合视频网址| 国产成人免费xxxxxxxx| 中文乱码人妻一区二区三区视频| 日本不卡免费高清视频| 一色桃子久久精品亚洲| 国产污视频在线| 欧美成人猛片aaaaaaa| 日韩免费高清在线观看| 欧美网站大全在线观看| 91人妻一区二区三区| 久久香蕉综合色| 日本在线观看网址| 欧美自拍大量在线观看| 精品久久久国产精品999| 性色av一区二区咪爱| 二个人看的毛片| 青青草视频成人| 日本久久一二三四| 欧美男女交配视频| 婷婷五月综合缴情在线视频| 亚洲色图另类图片| 手机在线视频你懂的| 亚洲免费视频在线观看| 国产乱子轮xxx农村| 美女视频黄频大全不卡视频在线播放| chinesegaysextube| 99久久精品久久久久久ai换脸| 日韩 欧美 中文| 99在线精品免费| 日本久久久久久久久久久| 国产日本欧美一区| 国产成人a亚洲精v品无码| 欧洲av在线精品| 激情中文字幕| 久久久久久久午夜| 88av在线| 久久精品国产一区二区三区不卡| 国产在线播放你懂的| 狠狠躁少妇一区二区三区| 婷婷激情五月网| 91亚洲一区| 精品少妇人妻av一区二区三区| 久久久久久久久久av| 四虎4hu新地址入口2023| 资源视频在线播放免费| 97福利电影| 精品无人区一区二区三区| 国产偷v国产偷v亚洲高清| 国模大胆一区二区三区| 国产精品51麻豆cm传媒| 国产成人a视频高清在线观看| 伊人免费视频二| 日韩美女av在线免费观看| 在线观看日韩中文字幕| 亚洲色图另类专区| 激情综合一区二区三区| 国产精品影视在线观看| 亚洲天堂av影院| 国产ts在线观看| 三级在线视频| 91精品福利| 欧美另类极品videosbest最新版本| 国产中文字幕久久| 欧美日韩无遮挡| 91色精品视频在线| 久久草av在线| 蜜桃精品在线| 免费拍拍拍网站| 亚洲午夜影视影院在线观看| 免费毛片在线播放免费| 视频一区视频二区视频三区视频四区国产| 国产精品久久久久久久久久久免费看| 色一情一乱一区二区三区| 精品人妻伦一二三区久| 天海翼一区二区三区四区在线观看| 亚洲欧美中文日韩在线v日本| 午夜视频久久久| 美女被人操视频在线观看| 午夜婷婷在线观看| 亚洲午夜在线| 在线一区日本视频| 美女999久久久精品视频| 色综合亚洲欧洲| 99精品视频在线观看播放| 日本新janpanese乱熟| 久久久精品影院| 又粗又硬又爽国产视频| 中文字幕福利片| 日韩中文影院| 成人免费无遮挡| a级在线观看视频| 欧美性bbwbbwbbwhd| ㊣最新国产の精品bt伙计久久| 成人性生交大片| 九色91视频| 伊人久久综合网另类网站| 神马电影网我不卡| 中文字幕色网站| 神马一区二区影院| 国产极品粉嫩福利姬萌白酱| 无码人妻精品一区二区三区99不卡| 精品无人区卡一卡二卡三乱码免费卡| 欧美一级视频免费观看| 精品影片在线观看的网站| 成码无人av片在线观看网站| 亚洲综合五月天| 国产人妻人伦精品1国产丝袜| 国产欧美一区二区三区米奇| 美日韩精品视频免费看| 销魂美女一区二区三区视频在线| 欧美三级日本三级少妇99| 国内外免费激情视频| 呦视频在线一区二区三区| 亚洲 精品 综合 精品 自拍| 热久久最新网址| 在线看日韩av| 91九色02白丝porn| 欧美视频在线观看一区| 欧美一区二区视频网站| 婷婷色综合网| 午夜影院在线播放| 欧美在线一区二区| 国产精品国产亚洲精品看不卡15| 91九色鹿精品国产综合久久香蕉| 青春草在线视频观看| 免费成人高清在线视频theav| 国产成人精品一区二区三区网站观看| 91精品在线观看国产| 欧美一级精品在线| 中文字幕在线视频一区| 特黄特色免费视频| 久久偷拍免费视频| 欧美国产欧美亚州国产日韩mv天天看完整| 91高清一区| 激情小说综合网| 精品国自产拍在线观看| 日韩三级电影免费观看| 99久久久无码国产精品免费| 沈樵精品国产成av片| 激情五月婷婷在线| 国精产品一区一区三区视频| 亚洲欧美小说国产图片| 蜜桃视频涩涩| 熟妇人妻中文av无码| 成人激情直播| 日韩av电影免费在线| 成人高清av在线| 欧美黑人一级爽快片淫片高清| 亚洲色图另类色图| 亚洲精品中文字幕99999| 欧美壮男野外gaytube| 日本电影免费看| 欧美一区二区视频免费观看| 99国产精品免费网站| 久久午夜a级毛片| 日本一区二区高清视频| 2019日本中文字幕| 久久免费播放视频| 乱小说欧美综合| 欧美亚洲成人精品| 亚洲已满18点击进入久久| 欧美精品国产精品| 高跟丝袜一区二区三区| 九色porny视频国产网曝| 亚洲成在人线av| 91精品久久久久久粉嫩| 精品乱子伦一区二区三区| 真实新婚偷拍xxxxx| 欧美特黄aaaaaaaa大片| 国产一区二区动漫| 国产不卡在线观看| 国产精品成人免费视频| 奇米777国产一区国产二区| 欧美日韩精品一区二区三区视频| 国产精品久久久久久免费播放| caopon在线免费视频| 亚洲高清在线视频| 欧美日韩亚洲丝袜制服| 国产欧美久久一区二区三区| 色在线中文字幕| 最新国产露脸在线观看| 日韩电影免费观看在| av在线观看地址| 欧美ab在线视频| 婷婷综合在线观看| 成人免费视频国产免费观看| 欧美巨大xxxx| 欧美日韩色综合| 在线观看精品一区二区三区| 亚洲综合无码一区二区| 国产精品九色蝌蚪自拍| 日韩理论在线观看| 欧美91在线|欧美| 亚洲免费高清视频在线| 一区二区三区视频免费视频观看网站| 久久久久久久久综合影视网| 亚洲国产精品传媒在线观看| 无码少妇精品一区二区免费动态| www视频在线看| 久久精品欧美视频| 亚洲美女自拍视频| 亚洲欧美www| 日韩网站在线免费观看| 国产精品久久久久久吹潮| 欧美极品在线视频| 99re6这里只有精品视频在线观看| 成人午夜毛片| va天堂va亚洲va影视| 亚洲天堂久久久| 在线这里只有精品| 中文字幕欧美日韩一区二区三区| 毛片在线播放a| 色婷婷久久99综合精品jk白丝| 欧美日韩一区二区免费在线观看| 中国老熟女重囗味hdxx| a黄色片在线观看| 中文字幕在线观看播放| 国产传媒欧美日韩成人| 99热这里只有精品在线观看| 一区二区久久久| 2019中文字幕在线电影免费| 亚洲色图偷拍自拍| 午夜福制92视频| av福利导福航大全在线播放| 欧美性活一级视频| kk眼镜猥琐国模调教系列一区二区| 美国欧美日韩国产在线播放| 91av手机在线| 久热精品在线观看| 69久久精品| 小嫩苞一区二区三区| www黄色在线| 牛牛精品视频在线| 亚洲精品成人精品456| 俺去了亚洲欧美日韩| 亚洲高清乱码| 精品国产乱码久久久久久免费| 亚洲欧美在线aaa| 四虎永久网址| 精品视频在线观看一区| 美女网站视频黄色| 青青草精品视频| 精品国产无码一区二区三区| 亚洲精品视频网| 制服丝袜在线第一页| 免费在线一区二区| www国产黄色| 色综合天天综合给合国产| 91精彩在线视频| 国产天堂第一区| 欧美成人免费在线| 精品视频自拍| 中文字幕精品在线视频|