婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > Mybatis調用PostgreSQL存儲過程實現數組入參傳遞

Mybatis調用PostgreSQL存儲過程實現數組入參傳遞

熱門標簽:辦公外呼電話系統 重慶自動外呼系統定制 外呼調研系統 打電話智能電銷機器人授權 合肥公司外呼系統運營商 地圖標注和圖片名稱的區別 美容工作室地圖標注 海豐有多少商家沒有地圖標注 漯河外呼電話系統

前言

項目中用到了Mybatis調用PostgreSQL存儲過程(自定義函數)相關操作,由于PostgreSQL自帶數組類型,所以有一個自定義函數的入參就是一個int數組,形如:

復制代碼 代碼如下:
CREATE OR REPLACE FUNCTION "public"."func_arr_update"(ids _int4)...

如上所示,參數是一個int數組,Mybatis提供了對調用存儲過程的支持,那么PostgreSQL獨有的數組類型作為存儲過程的參數又將如何處理呢?其實很簡單,mybatis提供了typeHandlers可以創建一個數組類型的類型處理器,具體做法為:實現 org.apache.ibatis.type.TypeHandler 接口, 或繼承一個很便利的類 org.apache.ibatis.type.BaseTypeHandler, 然后可以選擇性地將它映射到一個 JDBC 類型,先稍作了解,后面再做詳細說明,接下來依舊結合一個示例來看看。

創建自定義函數

如圖,第一步首先是創建一個用于調用的自定義函數,功能也很簡單,遍歷參數數組的每一個元素和t_student表的stuid做比較,若一致,則修改那條記錄的stuname(在其后拼接一段字符串),該自定義函數的DLL語句如下:

CREATE OR REPLACE FUNCTION "public"."func_arr_update"(ids _int4)
 RETURNS "pg_catalog"."void" AS $BODY$
DECLARE
   scount INTEGER;
   rownum integer := 1;
BEGIN
    scount:=array_length(ids,1);
    while rownum = scount LOOP
      update t_student set stuname = stuname || ' has been modified. ' where stuid = ids[rownum];
      rownum := rownum + 1;
  END LOOP;
  RETURN;
END
$BODY$
 LANGUAGE 'plpgsql' VOLATILE COST 100
;

ALTER FUNCTION "public"."func_arr_update"(ids _int4) OWNER TO "postgres";

很簡單,獲取到參數數組的長度后開始循環,匹配stuid并更新stuname,直接在數據庫調用一下看看結果:

如上圖,可以看到成功修改了stuid為101,102和103的stuname,自定義函數已經沒問題了,接下來就具體看一下如何通過mybatis調用。

調用自定義函數

mybatis中調用自定義函數很簡單,Mapper XML文件中的select元素直接提供了屬性支持——statementType,在官方文檔中可以看到:

如上圖,statementType的值默認是PREPARED,也就是說底層默認會使用jdbc的PreparedStatement,而我們都知道jdbc調用存儲過程時需要用CallableStatement,所以在這里我們需要將statementType的值設置為CALLABLE。

mybatis默認的ArrayTypeHandler

調用存儲過程很簡單,那么接下來的問題是如何在mybatis中傳一個數組參數到存儲過程中呢?這里就要用到另外一個概念——TypeHandler,這是mybatis提供的自定義類型轉換器,mybatis在預編譯語句對象(PreparedStatement)設置參數時或是從結果集中取值時都會用類型處理器將獲取的值以合適的方式轉換成Java類型,mybatis默認實現了一部分TypeHandler供我們使用,當我們沒有指定TypeHandler時(大多數情況都不會指定),mybatis會根據參數或者返回結果的不同,默認為我們選擇合適的TypeHandler處理,下面可以通過查看源碼大概看一下默認的TypeHandler,導入源碼后可以在org.apache.ibatis.type包下找到一個TypeHandlerRegistry類,typeHandler正是通過這個類管理的,先看一下它的構造方法:

 public TypeHandlerRegistry() {
  register(Boolean.class, new BooleanTypeHandler());
  register(boolean.class, new BooleanTypeHandler());
  register(JdbcType.BOOLEAN, new BooleanTypeHandler());
  register(JdbcType.BIT, new BooleanTypeHandler());

  register(Byte.class, new ByteTypeHandler());
  register(byte.class, new ByteTypeHandler());
  register(JdbcType.TINYINT, new ByteTypeHandler());

  register(Short.class, new ShortTypeHandler());
  register(short.class, new ShortTypeHandler());
  register(JdbcType.SMALLINT, new ShortTypeHandler());

  register(Integer.class, new IntegerTypeHandler());
  register(int.class, new IntegerTypeHandler());
  register(JdbcType.INTEGER, new IntegerTypeHandler());

  register(Long.class, new LongTypeHandler());
  register(long.class, new LongTypeHandler());

  register(Float.class, new FloatTypeHandler());
  register(float.class, new FloatTypeHandler());
  register(JdbcType.FLOAT, new FloatTypeHandler());

  register(Double.class, new DoubleTypeHandler());
  register(double.class, new DoubleTypeHandler());
  register(JdbcType.DOUBLE, new DoubleTypeHandler());

  register(String.class, new StringTypeHandler());
  register(String.class, JdbcType.CHAR, new StringTypeHandler());
  register(String.class, JdbcType.CLOB, new ClobTypeHandler());
  register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
  register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
  register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
  register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
  register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
  register(JdbcType.CHAR, new StringTypeHandler());
  register(JdbcType.VARCHAR, new StringTypeHandler());
  register(JdbcType.CLOB, new ClobTypeHandler());
  register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
  register(JdbcType.NVARCHAR, new NStringTypeHandler());
  register(JdbcType.NCHAR, new NStringTypeHandler());
  register(JdbcType.NCLOB, new NClobTypeHandler());

  register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
  register(JdbcType.ARRAY, new ArrayTypeHandler());

  register(BigInteger.class, new BigIntegerTypeHandler());
  register(JdbcType.BIGINT, new LongTypeHandler());

  register(BigDecimal.class, new BigDecimalTypeHandler());
  register(JdbcType.REAL, new BigDecimalTypeHandler());
  register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
  register(JdbcType.NUMERIC, new BigDecimalTypeHandler());

  register(Byte[].class, new ByteObjectArrayTypeHandler());
  register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
  register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
  register(byte[].class, new ByteArrayTypeHandler());
  register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
  register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
  register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
  register(JdbcType.BLOB, new BlobTypeHandler());

  register(Object.class, UNKNOWN_TYPE_HANDLER);
  register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
  register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);

  register(Date.class, new DateTypeHandler());
  register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
  register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
  register(JdbcType.TIMESTAMP, new DateTypeHandler());
  register(JdbcType.DATE, new DateOnlyTypeHandler());
  register(JdbcType.TIME, new TimeOnlyTypeHandler());

  register(java.sql.Date.class, new SqlDateTypeHandler());
  register(java.sql.Time.class, new SqlTimeTypeHandler());
  register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());

  // issue #273
  register(Character.class, new CharacterTypeHandler());
  register(char.class, new CharacterTypeHandler());
 }

如上所示,這就是全部默認的typeHandler了,注意一下46,47行可以看到默認有一個ArrayTypeHandler,順便看一下它的源碼:

/*
 *  Copyright 2009-2012 The MyBatis Team
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.apache.ibatis.type;

import java.sql.Array;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class ArrayTypeHandler extends BaseTypeHandlerObject> {

 public ArrayTypeHandler() {
  super();
 }

 @Override
 public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
  ps.setArray(i, (Array) parameter);
 }

 @Override
 public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
  Array array = rs.getArray(columnName);
  return array == null ? null : array.getArray();
 }

 @Override
 public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
  Array array = rs.getArray(columnIndex);
  return array == null ? null : array.getArray();
 }

 @Override
 public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
  Array array = cs.getArray(columnIndex);
  return array == null ? null : array.getArray();
 }

}

那它能否識別PostgreSQL的數組類型并將它自動轉換成Java數組類型呢?按官方的說法,既然這是默認的typeHandler,那么我們無需做任何配置mybatis會自動嘗試適配,所以直接寫測試代碼看看:

@Test
public void testFunc1() {
  SqlSession session = sqlSessionFactory.openSession();
  try {
    MapString, Object> map = new HashMapString, Object>();
    map.put("ids", new Integer[] { 101, 102, 103 });
    session.update("com.wl.entity.StudentMapper.testFuncUpdate2", map);
    session.commit();
  } catch (Exception e) {
    e.printStackTrace();
  } finally {
    session.close();
  }
}
update id="testFuncUpdate2" statementType="CALLABLE">
  {call func_arr_update (#{ids,mode=IN})} 
/update>

如上所示,參數傳的是一個Integer[],直接運行一下junit看看測試結果:

Can't infer the SQL type to use for an instance of [Ljava.lang.Integer;. Use setObject() with an explicit Types value to specify the type to use.

異常log如上所示,在調用AbstractJdbc2Statement類的setObject方法時拋出異常,那么再看看這個方法的源碼:

  /*
   * This stores an Object into a parameter.
   */
  public void setObject(int parameterIndex, Object x) throws SQLException
  {
    checkClosed();
    if (x == null)
      setNull(parameterIndex, Types.OTHER);
    else if (x instanceof String)
      setString(parameterIndex, (String)x);
    else if (x instanceof BigDecimal)
      setBigDecimal(parameterIndex, (BigDecimal)x);
    else if (x instanceof Short)
      setShort(parameterIndex, ((Short)x).shortValue());
    else if (x instanceof Integer)
      setInt(parameterIndex, ((Integer)x).intValue());
    else if (x instanceof Long)
      setLong(parameterIndex, ((Long)x).longValue());
    else if (x instanceof Float)
      setFloat(parameterIndex, ((Float)x).floatValue());
    else if (x instanceof Double)
      setDouble(parameterIndex, ((Double)x).doubleValue());
    else if (x instanceof byte[])
      setBytes(parameterIndex, (byte[])x);
    else if (x instanceof java.sql.Date)
      setDate(parameterIndex, (java.sql.Date)x);
    else if (x instanceof Time)
      setTime(parameterIndex, (Time)x);
    else if (x instanceof Timestamp)
      setTimestamp(parameterIndex, (Timestamp)x);
    else if (x instanceof Boolean)
      setBoolean(parameterIndex, ((Boolean)x).booleanValue());
    else if (x instanceof Byte)
      setByte(parameterIndex, ((Byte)x).byteValue());
    else if (x instanceof Blob)
      setBlob(parameterIndex, (Blob)x);
    else if (x instanceof Clob)
      setClob(parameterIndex, (Clob)x);
    else if (x instanceof Array)
      setArray(parameterIndex, (Array)x);
    else if (x instanceof PGobject)
      setPGobject(parameterIndex, (PGobject)x);
    else if (x instanceof Character)
      setString(parameterIndex, ((Character)x).toString());
    else if (x instanceof Map)
      setMap(parameterIndex, (Map)x);
    else
    {
      // Can't infer a type.
      throw new PSQLException(GT.tr("Can''t infer the SQL type to use for an instance of {0}. Use setObject() with an explicit Types value to specify the type to use.", x.getClass().getName()), PSQLState.INVALID_PARAMETER_TYPE);
    }
  }

我們參數傳進去的Integer[]數組是一個Object數組,而 setObject(int parameterIndex, Object x)方法的第二個參數是Object,所以這里這里自然無法匹配也就報錯了,那么換成int[]可以嗎?在上面的else if語句中明顯沒有x instanceof int[]這行代碼,所以當然也不行,說到這里也就明確了mybatis默認提供的ArrayTypeHandler是無法自動識別PostgreSQL的數組類型,我們必須自定義一個參數為Object[]的ArrayTypeHandler才能實現匹配。

自定義ArrayTypeHandler

如題,先貼上代碼:

package com.wl.util;

import java.sql.Array;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.TypeException;

@MappedJdbcTypes(JdbcType.ARRAY)
public class ArrayTypeHandler extends BaseTypeHandlerObject[]> {

  private static final String TYPE_NAME_VARCHAR = "varchar";
  private static final String TYPE_NAME_INTEGER = "integer";
  private static final String TYPE_NAME_BOOLEAN = "boolean";
  private static final String TYPE_NAME_NUMERIC = "numeric";

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i,
      Object[] parameter, JdbcType jdbcType) throws SQLException {

    String typeName = null;
    if (parameter instanceof Integer[]) {
      typeName = TYPE_NAME_INTEGER;
    } else if (parameter instanceof String[]) {
      typeName = TYPE_NAME_VARCHAR;
    } else if (parameter instanceof Boolean[]) {
      typeName = TYPE_NAME_BOOLEAN;
    } else if (parameter instanceof Double[]) {
      typeName = TYPE_NAME_NUMERIC;
    }

    if (typeName == null) {
      throw new TypeException(
          "ArrayTypeHandler parameter typeName error, your type is "
              + parameter.getClass().getName());
    }

    Connection conn = ps.getConnection();
    Array array = conn.createArrayOf(typeName, parameter);
    ps.setArray(i, array);
  }

  @Override
  public Object[] getNullableResult(ResultSet rs, String columnName)
      throws SQLException {

    return getArray(rs.getArray(columnName));
  }

  @Override
  public Object[] getNullableResult(ResultSet rs, int columnIndex)
      throws SQLException {

    return getArray(rs.getArray(columnIndex));
  }

  @Override
  public Object[] getNullableResult(CallableStatement cs, int columnIndex)
      throws SQLException {

    return getArray(cs.getArray(columnIndex));
  }

  private Object[] getArray(Array array) {

    if (array == null) {
      return null;
    }

    try {
      return (Object[]) array.getArray();
    } catch (Exception e) {
    }

    return null;
  }
}

如上所示,我們指定了參數類型為Object[],這樣就可以接收Integer[]類型的參數了,關鍵是44~46行,postgresql的驅動類AbstractJdbc4Connection實現了Connect接口的createArrayOf方法,源碼如下:

  public Array createArrayOf(String typeName, Object[] elements) throws SQLException
  {
    checkClosed();
    int oid = getTypeInfo().getPGArrayType(typeName);
    if (oid == Oid.UNSPECIFIED)
      throw new PSQLException(GT.tr("Unable to find server array type for provided name {0}.", typeName), PSQLState.INVALID_NAME);

    char delim = getTypeInfo().getArrayDelimiter(oid);
    StringBuffer sb = new StringBuffer();
    appendArray(sb, elements, delim);

    // This will not work once we have a JDBC 5,
    // but it'll do for now.
    return new Jdbc4Array(this, oid, sb.toString());
  }

這樣通過自定義的ArrayTypeHandler就可以在Mybatis中方便的操作數組類型數據了,最后再測試一下,測試類代碼不變,僅需在調用存儲過程時指定mapper文件的typeHandler即可:

@Test
public void testFunc1() {
  SqlSession session = sqlSessionFactory.openSession();
  try {
    MapString, Object> map = new HashMapString, Object>();
    map.put("ids", new Integer[] { 101, 102, 103 });
    session.update("com.wl.entity.StudentMapper.testFuncUpdate2", map);
    session.commit();
  } catch (Exception e) {
    e.printStackTrace();
  } finally {
    session.close();
  }
}


update id="testFuncUpdate2" statementType="CALLABLE">
  {call func_arr_update (#{ids,mode=IN,typeHandler=com.wl.util.ArrayTypeHandler})} 
/update>

再次運行junit看一下測試結果:

如上所示,此時已經可以成功調用參數為Integer[]數組的pg自定義函數了。

總結

簡單記錄一下在mybatis中調用postgresql自定義函數時傳遞數組參數的解決方案,希望對遇到同樣問題的朋友有所幫助,The End。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

您可能感興趣的文章:
  • MyBatis傳入參數為List對象的實現
  • mybatis條件語句中帶數組參數的處理
  • MyBatis傳入數組集合類并使用foreach遍歷
  • 基于mybatis中數組傳遞注意事項

標簽:衡陽 來賓 錦州 蚌埠 株洲 烏海 晉城 珠海

巨人網絡通訊聲明:本文標題《Mybatis調用PostgreSQL存儲過程實現數組入參傳遞》,本文關鍵詞  Mybatis,調用,PostgreSQL,存儲,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《Mybatis調用PostgreSQL存儲過程實現數組入參傳遞》相關的同類信息!
  • 本頁收集關于Mybatis調用PostgreSQL存儲過程實現數組入參傳遞的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    日本中文一区二区三区| 亚洲日本在线视频观看| 欧美视频一区二区三区在线观看 | 亚洲va欧美va国产va天堂影院| 黄色日韩三级电影| 欧美人伦禁忌dvd放荡欲情| 国产精品福利av| 国产成人av福利| 国产欧美一区二区三区沐欲| 久久精品av麻豆的观看方式| 欧美人与禽zozo性伦| 视频在线观看一区| 2024国产精品视频| 国产成人午夜精品5599| 91精品国产福利| 蜜桃精品视频在线| 久久伊人蜜桃av一区二区| 国产成人免费高清| 亚洲视频在线一区二区| 欧美视频一区二区三区| 亚洲国产成人av好男人在线观看| 欧美在线免费观看视频| 亚洲第一福利一区| 日韩精品一区二区三区四区视频| 日韩极品在线观看| 久久精品欧美一区二区三区麻豆| 国产综合久久久久影院| 亚洲四区在线观看| 精品剧情v国产在线观看在线| 国产成人精品一区二| 亚洲九九爱视频| 日韩欧美一区二区不卡| 色综合天天天天做夜夜夜夜做| 偷拍与自拍一区| 一区二区三区电影在线播| 精品久久人人做人人爱| 欧美日韩一级片在线观看| 国产经典欧美精品| 国产乱码精品一品二品| 蜜臀av性久久久久蜜臀aⅴ| 亚洲gay无套男同| 中文一区在线播放| 欧美美女直播网站| 51午夜精品国产| 日韩色视频在线观看| 欧美日韩视频在线观看一区二区三区| av动漫一区二区| 色综合欧美在线| 色94色欧美sute亚洲线路一ni| 国产麻豆精品95视频| 蜜臀av性久久久久蜜臀av麻豆| 美女视频黄 久久| 成人一区二区三区在线观看| 国产精品一线二线三线精华| 激情亚洲综合在线| zzijzzij亚洲日本少妇熟睡| 日本道色综合久久| 在线播放亚洲一区| 久久久久久夜精品精品免费| 亚洲欧洲av色图| 免费的国产精品| 91丨九色丨尤物| 精品国产一区二区三区忘忧草| 国产精品久久福利| 久国产精品韩国三级视频| av一二三不卡影片| 精品成人在线观看| 日日夜夜免费精品| 色偷偷成人一区二区三区91| 制服丝袜在线91| 亚洲成人自拍网| 色综合久久久久网| 国产视频一区二区在线观看| 日韩电影在线一区二区三区| 99re在线精品| 成人深夜在线观看| 666欧美在线视频| 亚洲成va人在线观看| 一本色道久久加勒比精品| 亚洲精品一区二区三区99| 三级不卡在线观看| 久久久久国产精品麻豆ai换脸| 亚洲美女在线国产| 色视频成人在线观看免| 亚洲欧美经典视频| 在线观看视频一区二区欧美日韩| 国产亚洲一二三区| 成人激情文学综合网| 亚洲欧美激情在线| 91精品国产综合久久婷婷香蕉| 亚洲国产欧美另类丝袜| 欧美酷刑日本凌虐凌虐| 开心九九激情九九欧美日韩精美视频电影 | 国产精品一二二区| 久久色在线视频| 国产精品亚洲第一区在线暖暖韩国 | 国产99久久久国产精品潘金| 中国av一区二区三区| 91麻豆123| 粉嫩av一区二区三区| 亚洲成a人片综合在线| 精品国产乱码久久久久久闺蜜 | 欧美色图片你懂的| 国产精品自拍av| 天天影视涩香欲综合网| 国产精品理论在线观看| 欧美久久高跟鞋激| av电影一区二区| 成人综合在线视频| 久久精品国产亚洲aⅴ| 伊人性伊人情综合网| 久久久蜜桃精品| 欧美一区二区三区公司| 色综合天天做天天爱| 99精品欧美一区二区蜜桃免费 | 国产精品一级片在线观看| 亚洲图片欧美一区| 午夜精品福利一区二区三区av| 伊人色综合久久天天人手人婷| 中文字幕一区二区三| 一区在线观看免费| 亚洲精品中文字幕在线观看| 亚洲欧洲av另类| 亚洲第一成年网| 久久国产精品露脸对白| 久久激情五月婷婷| 国产在线一区观看| 久久99国产精品免费网站| 精品一区二区在线观看| 成人免费毛片aaaaa**| 91蝌蚪porny成人天涯| 在线视频国内自拍亚洲视频| 欧美吻胸吃奶大尺度电影| 欧美性极品少妇| 精品少妇一区二区三区在线播放 | 91麻豆精品国产自产在线观看一区| 91国产精品成人| 久久久精品人体av艺术| 自拍偷在线精品自拍偷无码专区| 亚洲精品日产精品乱码不卡| 麻豆精品在线看| 色婷婷av一区二区三区之一色屋| 精品久久久网站| 日韩精品午夜视频| 一本大道综合伊人精品热热| 久久久亚洲欧洲日产国码αv| 亚洲午夜电影在线观看| 成人精品鲁一区一区二区| 日韩无一区二区| 日本成人在线网站| 精品视频999| 国产精品国产三级国产有无不卡| 日本91福利区| 日韩三级视频中文字幕| 偷拍日韩校园综合在线| 欧美日韩aaa| 麻豆成人91精品二区三区| 欧美亚男人的天堂| 亚洲va欧美va国产va天堂影院| 91麻豆自制传媒国产之光| 亚洲视频一区二区免费在线观看| 国产凹凸在线观看一区二区| 久久久五月婷婷| 一本到不卡免费一区二区| 亚洲国产一二三| 69久久夜色精品国产69蝌蚪网| 首页国产丝袜综合| 久久免费视频一区| 99久久久国产精品免费蜜臀| 一区二区三区四区在线免费观看| 欧洲色大大久久| 蜜臀av性久久久久蜜臀aⅴ流畅| 91精品欧美久久久久久动漫| 韩国av一区二区三区四区| 久久精品夜色噜噜亚洲a∨| 一本色道久久综合亚洲aⅴ蜜桃| 亚洲精品视频免费看| 欧美日韩不卡视频| 国产盗摄女厕一区二区三区| 亚洲激情一二三区| 久久久精品国产99久久精品芒果| 成人激情小说网站| 国产一区二区三区四区五区入口| 亚洲精选视频免费看| 欧美高清在线一区| 日韩精品一区二| 欧美性色黄大片| 欧美色综合网站| 欧美日韩高清一区二区| 精品视频123区在线观看| 91猫先生在线| 色综合久久综合| 激情图片小说一区| 国产成人自拍网| 国产一区二区福利视频| 亚洲图片欧美激情| 1000部国产精品成人观看| 国产精品久久久久9999吃药| 中文字幕精品三区| 亚洲婷婷综合色高清在线|